Bridge:
[Link] Name and Classification:
it conveys the essence of the pattern succinctly good name is vital, because it will
become part of design vocabulary.
[Link]:
Decouple an abstraction from its implementation so that the two can vary independently.
[Link] Known As: Handle/Body
[Link]:
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.
But this approach has two drawbacks:
It's inconvenient to extend the Window abstraction to cover different kinds
of windows or new platforms.
It makes client code platform-dependent.
[Link]:
Use the Bridge pattern when
you want to avoid a permanent binding between an abstraction and its
implementation.
both the abstractions and their implementations should be extensible by
subclassing.
changes in the implementation of an abstraction should have no impact on clients;
(C++) you want to hide the implementation of an abstraction completely from
clients.
you have a proliferation of classes as shown earlier in the first Motivation diagram.
you want to share an implementation among multiple objects, and this fact should
be hidden from the client.
[Link]:
[Link]:
Abstraction (Window)
defines the abstraction's interface.
maintains a reference to an object of type Implementor.
RefinedAbstraction (IconWindow)
Extends the interface defined by Abstraction.
Implementor (WindowImp)
defines the interface for implementation classes. Typically the Implementor
interface provides only primitive operations, and Abstraction defines
higher- level operations based on these primitives.
Concrete Implementor (XWindowImp, PMWindowImp)
implements the Implementor interface and defines its concrete implementation.
[Link]:
Abstraction forwards client requests to its Implementor object.
[Link]:
The Bridge pattern has the following consequences:
1. Decoupling interface and implementation.
⚫
An implementation is not bound permanently to an interface. 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.
[Link] 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).
[Link]:
Consider the following implementation issues when applying the Bridge pattern:
1. Only one Implementor. This is a degenerate case of the bridge pattern ; there is
one- to-one relationship between abstraction and implementor. There is one-to-one
relationship between abstraction and implementor.
Useful when a change in the implementation of a class must not affect its existing
clients
2. Creating the right Implementor object.
How, when, and where do you decide which Implementor class to
instantiate when there's more than one?
If abstraction knows about all concrete implementor classes, then it can instantiate
one of them in its constructor.
To choose a default implementation initially and change it later according to
usage.
3. Sharing implementors. The Body stores a reference count that the Handle class
increments and decrements.
4. Using multiple inheritance. You can use multiple inheritance in C++ to combine
an interface with its implementation.
[Link] Code:
class Window {
public:
Window(View* contents);
// requests handled by
window virtual void
DrawContents(); virtual
void Open();
virtual void Close();
virtual void Iconify();
virtual void
Deiconify();
// requests forwarded to
implementation virtual void
SetOrigin(const Point& at); virtual
void SetExtent(const Point& extent);
virtual void Raise();
virtual void Lower();
virtual void DrawLine(const Point&, const
Point&); virtual void DrawRect(const Point&,
const Point&); virtual void
DrawPolygon(const Point[], int n); virtual
void DrawText(const char*, const Point&);
protected:
WindowImp*
GetWindowImp(); View*
GetView();
private:
WindowImp* _imp;
View* _contents; // the window's contents };
[Link] Uses:
In ET++, WindowImp is called "WindowPort" and has subclasses such as
XWindowPort and SunWindowPort.
The ET++ Window/WindowPort design extends the Bridge pattern in
that the WindowPort also keeps a reference back to the Window.
libg++ defines classes that implement common data structures, such as Set,
LinkedSet, HashSet, LinkedList, and HashTable.
NeXT's AppKit uses the Bridge pattern in the implementation and display of
graphical images.
[Link] Patterns:
An Abstract Factory can create and configure a particular Bridge.
The Adapter pattern is geared toward making unrelated classes work together.