Design Patterns - Bridge

Design Patterns - Bridge

The Bridge design pattern allows you to separate the abstraction from the implementation.

Bridge pattern decouples implementation class and abstract class by providing a bridge structure between them.

Intent:

  • Decouple an abstraction from its implementation so that the two can vary independently.
  • Publish interface in an inheritance hierarchy, and bury implementation in its own inheritance hierarchy.
  • Beyond encapsulation, to insulation.

Problem:

"Hardening of the software arteries" has occurred by using subclassing of an abstract base class to provide alternative implementations. This locks in compile-time binding between interface and implementation. The abstraction and implementation cannot be independently extended or composed.

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 image.png Drawback 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.

Drawback 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.

Solution:

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. image.png 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.

Applicability:

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.

You want to share an implementation among multiple objects, 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).

Structure:

image.png

Abstraction -

  • Defines the abstraction's interface
  • Maintains a reference to an object of type Implementor. RefinedAbstraction - Extends the interface defined by Abstraction. Implementor - defines the interface for implementation classes. ConcreteImplementor - implements the Implementor interface and defines its concrete implementation.

Abstraction forwards client requests to its Implementor object

Consequences:

  • Decoupling interface and implementation.
  • Improved extensibility - You can extend the Abstraction and Implementer hierarchies independently.
  • Hiding implementation details from clients.

Known Uses:

In ET++, WindowImp is called "WindowPort" and has subclasses such as XWindowPort and SunWindowPort.

The Window object creates its corresponding Implementor object by requesting it from an abstract factory called "WindowSystem." WindowSystem provides an interface for creating platform-specific objects such as fonts, cursors, bitmaps, and so forth.

  • Abstract Factory
  • Adapter

Thank you for reading. Kindly give your valuable feedback and suggestions.

Did you find this article valuable?

Support Balasundar by becoming a sponsor. Any amount is appreciated!