Bridge Pattern

📢 This article was translated by gemini-2.5-flash

Bridge Pattern: Object Structural Pattern

Intent

Separate an abstraction from its implementation so that both can vary independently.

Structure

Bridge Pattern

Where:

  • Abstraction: Defines the abstract class interface. It maintains a pointer to an object of type Implementor.
  • RefinedAbstraction: Extends the interface defined by Abstraction.
  • Implementor: Defines the interface for implementation classes. This interface doesn’t have to be exactly the same as Abstraction’s interface; in fact, the two interfaces can be completely different. Generally, the Implementor interface provides only basic operations, while Abstraction defines higher-level operations based on these primitives.
  • ConcreteImplementor: Implements the Implementor interface and defines its concrete implementation.

Applicability

The Bridge pattern is useful when:

  • You don’t want a fixed binding between an abstraction and its implementation. For example, the implementation might need to be selected or switched at runtime.
  • Both the class abstraction and its implementation should be extensible via subclassing. The Bridge pattern allows developers to combine different abstract interfaces and implementations, and extend them independently.
  • Changes to an abstraction’s implementation should not affect clients. Client code shouldn’t need recompiling.
  • (C++) You want to completely hide the abstraction’s implementation from clients.
  • You have a class hierarchy with many classes to generate.
  • You want to share an implementation among multiple objects (possibly using reference counting), but without the client knowing about it.

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class main {
    public static void main(String[] args) {
        Product ProductA1 = new ProductA();
        Product ProductA2 = new ProductA();

        Color red = new Red();
        ProductA1.setName("P-A1");
        ProductA1.setColor(red);
        ProductA1.Operation;

        Color blue = new Blue();
        ProductA1.setName("P-A2");
        ProductA1.setColor(blue);
        ProductA1.Operation;
    }
}

abstract class Product{
    private String name;
    protected Color color;

    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }

    public setColor(Color color){
        this.color = color;
    }

    public abstract void Operation();
} 

class ProductA extends Product{
    @Override
    public void Operation(){
        color.OperationImp(this.getName());
    }
}

class Color{
    public void OperationImp(String name);
}

class Red extends Color{
    @Override
    public void OperationImp(String name){
        System.out.println(name + ": red")
    }
}

class Blue extends Color{
    @Override
    public void OperationImp(String name){
        System.out.println(name + ": blue")
    }
}