Creational Patterns ( ์ƒ์„ฑ ํŒจํ„ด )

These design patterns provides way to create objects while hiding the creation logic, rather than instantiating objects directly using new operator. This gives program more flexibility in deciding which objects need to be created for a given use case. 

์ƒ์„ฑํŒจํ„ด์€ ๊ฐ์ฒด์˜ ์ƒ์„ฑ๋กœ์ง์„ ์ˆจ๊ธฐ๊ณ  new ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•˜์ง€ ์•Š๊ณ  ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•๋“ค์„ ์ œ๊ณตํ•œ๋‹ค. ์ด๋Š” ํŠน์ • ์ƒํ™ฉ์—์„œ ์–ด๋–ค ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์•ผํ• ์ง€๋ฅผ ๊ฒฐ์ •ํ•˜๋Š”๋ฐ ์žˆ์–ด์„œ ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค. 


 Structural Patterns ( ๊ตฌ์กฐ์  ํŒจํ„ด )

These design patterns concern class and object composition. Concept of inheritance is used to compose interfaces and define ways to compose objects to obtain new functionalities. 

๊ตฌ์กฐ์  ํŒจํ„ด๋“ค์€ ํด๋ž˜์Šค์™€ ๊ฐ์ฒด์˜ ๊ตฌ์„ฑ์— ๊ด€์—ฌํ•œ๋‹ค.

 

 Behavioral Patterns ( ํ–‰์œ„์  ํŒจํ„ด )

These design patterns are specifically concerned with communication between objects.

์ด ํŒจํ„ด๋“ค์€ ๊ฐ์ฒด๋“ค ์‚ฌ์ด์˜ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜์— ๊ด€์‹ฌ์„ ๊ฐ€์ง„๋‹ค.

 

์˜ค๋Š˜ ์‚ดํŽด๋ณผ  Bridge ํŒจํ„ด์€ Structural ํŒจํ„ด์— ์†ํ•œ๋‹ค.  

 

๋ง๊ทธ๋Œ€๋กœ A์™€ B๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๋‹ค๋ฆฌ์—ญํ• ์„ ํ•˜๋Š” ํŒจํ„ด์ด๋‹ค. 

 

Bridge Pattern Structure



 


ํŒจํ„ด์˜ ๋ชฉ์  ( Intent ) : 

Decouple an abstraction from its implementation so that the two can vary independently.

๋ธŒ๋ฆฌ์ง€ ํŒจํ„ด์€ ์–ด๋Œ‘ํ„ฐ ํŒจํ„ด๊ณผ ๋น„์Šทํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ ๋ชฉ์ ์ด ๋ถ„๋ช…ํžˆ ๋‹ค๋ฆ„์„ ์ˆ™์ง€ํ•ด์•ผํ•œ๋‹ค. ๋ธŒ๋ฆฌ์ง€ ํŒจํ„ด์€ ์ถ”์ƒํ™”๋ฅผ ํ•จ์œผ๋กœ์จ ๋‘๊ฐœ๋ฅผ ๊ตฌ๋ถ„์ง“๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ํŒจํ„ด์ด๋‹ค.

 

 

ํŒจํ„ด์ด ๋‚˜์˜ค๊ฒŒ ๋œ ๋™๊ธฐ ( Motivation ) :

When an abstraction can have one of several possible implementations, the usual way to accommodate them is to use inheritance. An abstract class defines the interface to the abstraction, and concrete subclasses implement it in different ways. But this approach isn't always flexible enough. Inheritance binds an implementation to the abstraction permanently, which makes it difficult to modify, extend, and reuse abstractions and implementations independently.
Consider the implementation of a portable Window abstraction in a user interface toolkit. This abstraction should enable us to write applications that work on both the X Window System and IBM's Presentation Manager (PM), for example. Using inheritance, we could define an abstract class Window and subclasses XWindow and PMWindow that implement the Window interface for the different platforms. But this approach has two drawbacks:


1. It's inconvenient to extend the Window abstraction to cover different kinds
of windows or new platforms. Imagine an IconWindow subclass of Window that
specializes the Window abstraction for icons. To support IconWindows for
both platforms, we have to implement two new classes, XIconWindow and
PMIconWindow. Worse, we'll have to define two classes for every kind of
window. Supporting a third platform requires yet another new Window subclass
for every kind of window.

 


2. It makes client code platform-dependent. Whenever a client creates a window, it instantiates a concrete class that has a specific implementation. For example, creating an XWindow object binds the Window abstraction to the X Window implementation, which makes the client code dependent on the X Window implementation. This, in turn, makes it harder to port the client code to other platforms.


Clients should be able to create a window without committing to a concrete implementation. Only the window implementation should depend on the platform on which the application runs.  Therefore client code should instantiate windows without mentioning specific platforms. 

 

The Bridge pattern addresses these problems by putting the Window abstraction and its implementation in separate class hierarchies. There is one class hierarchy for window interfaces (Window, IconWindow, TransientWindow) and a separate hierarchy for platform-specific window implementations, with WindowImp as its root. The XWindowImp subclass, for example, provides an implementation based on the X Window System. 

 



์œ ์šฉ์„ฑ ( Applicability ) :

Use the Bridge pattern when
ยท you want to avoid a permanent binding between an abstraction and its implementation. This might be the case, for example, when the implementation must be selected or switched at  run-time.
ยท both the abstractions and their implementations should be extensible by subclassing. In this case, the Bridge pattern lets you combine the different abstractions and implementations and extend them independently.
ยท changes in the implementation of an abstraction should have no impact on clients; that is, their code should not have to be recompiled.
ยท (C++) you want to hide the implementation of an abstraction completely from clients. In C++ the representation of a class is visible in the class interface.
ยท you have a proliferation of classes as shown earlier in the first Motivation diagram. Such a class hierarchy indicates the need for splitting an object into two parts. Rumbaugh uses the term "nested generalizations"  to refer to such class hierarchies.
ยท you want to share an implementation among multiple objects (perhaps using reference counting), and this fact should be hidden from the client. A simple example is Coplien's String class , in which multiple objects can share the same string representation (StringRep).

 

๋“ฑ์žฅ ์ธ๋ฌผ ( Participants ) :

ยท Abstraction (Window)
o defines the abstraction's interface.
o maintains a reference to an object of type Implementor.

ยท RefinedAbstraction (IconWindow)
o Extends the interface defined by Abstraction.
ยท Implementor (WindowImp)
o defines the interface for implementation classes. This interface doesn't have to correspond exactly to Abstraction's interface; in fact the two interfaces can be quite different. Typically the
Implementor interface provides only primitive operations, and Abstraction defines higher-level operations based on these primitives.

ยท ConcreteImplementor (XWindowImp, PMWindowImp)
o implements the Implementor interface and defines its concrete implementation.


 

 All operations on Window subclasses are implemented in terms of abstract operations from the WindowImp interface. This decouples the window abstractions from the various platform-specific implementations. We refer to the relationship between Window and WindowImp as a bridge,  because it bridges the abstraction and its implementation, letting them vary independently.


์›๋ฆฌ ( Collaborations ) :

ยท Abstraction forwards client requests to its Implementor object.


ํŒจํ„ด ์‚ฌ์šฉ์˜ ์žฅ๋‹จ์  ( Consequences ): 

The Bridge pattern has the following consequences:


1. Decoupling interface and implementation. An implementation is not bound permanently to an interface. The implementation of an abstraction can be configured at run-time. It's even possible for an object to change its implementation at run-time.
Decoupling Abstraction and Implementor also eliminates compile-time dependencies on the implementation. Changing an implementation class doesn't require recompiling the Abstraction class and its clients. This property is essential when you must ensure binary compatibility between different versions of a class library.
Furthermore, this decoupling encourages layering that can lead to a better-structured system. The high-level part of a system only has to know about Abstraction and Implementor. 

 

2. Improved extensibility. You can extend the Abstraction and Implementor hierarchies independently.


3. Hiding implementation details from clients. You can shield clients from implementation details, like the sharing of implementor objects and the accompanying reference count mechanism (if any).


๊ด€๋ จ ํŒจํ„ด๋“ค : 

An Abstract Factory can create and configure a particular Bridge.
The Adapter pattern
is geared toward making unrelated classes work together. It is usually applied to systems after they're designed. Bridge, on the other hand, is used up-front in a design to let abstractions and implementations vary independently.

 

์ถ”๊ฐ€ ์ •๋ณด :     

  • Adapter makes things work after they're designed; Bridge makes them work before they are.
  • Bridge is designed up-front to let the abstraction and the implementation vary independently. Adapter is retrofitted to make unrelated classes work together.
  • State, Strategy, Bridge (and to some degree Adapter) have similar solution structures. They all share elements of the "handle/body" idiom. They differ in intent - that is, they solve different problems.
  • The structure of State and Bridge are identical (except that Bridge admits hierarchies of envelope classes, whereas State allows only one). The two patterns use the same structure to solve different problems: State allows an object's behavior to change along with its state, while Bridge's intent is to decouple an abstraction from its implementation so that the two can vary independently.
  • If interface classes delegate the creation of their implementation classes (instead of creating/coupling themselves directly), then the design usually uses the Abstract Factory pattern to create the implementation objects.

 

 

 

์ถœ์ฒ˜ : http://sourcemaking.com/design_patterns/bridge

         Design Patterns : Element of Reusable Object Oriented Software ( by GoF, 1994 )