The bridge pattern decouples an abstraction from its implementation so that the two can vary independently. Instead of inheriting a concrete color into each shape class, the shape holds a reference to an abstract color — the bridge — and delegates color queries through that reference. The key principle: program to an interface, not an implementation.
Roles
- Implementor — defines the interface for concrete implementors. Does not need to match the abstraction's interface; it provides the low-level operations the abstraction calls.
- Concrete Implementor — implements the implementor interface with a specific behaviour.
- Abstraction — holds a reference of type Implementor and defines high-level operations built on it.
- Refined Abstraction — extends the abstraction with additional operations or overrides.
Implementor
csharp
// Implementor — abstract base that all concrete colors must implement.
// The abstraction (Shape) holds a reference to this type, never a concrete class.
public abstract class Color
{
public abstract int Red { get; }
public abstract int Green { get; }
public abstract int Blue { get; }
}Concrete Implementors
csharp
// Concrete implementors — vary independently from the shapes that use them.
// One instance of each color can be shared across many shapes (flyweight-like).
public class ColorRed : Color
{
public override int Red => 255;
public override int Green => 0;
public override int Blue => 0;
}
public class ColorYellow : Color
{
public override int Red => 255;
public override int Green => 255;
public override int Blue => 0;
}Abstraction
csharp
// Abstraction — holds the implementor by reference.
// Works with Color (the interface), never with ColorRed or ColorYellow directly.
public abstract class Shape
{
protected Color Color;
public Shape(Color color)
{
Color = color;
}
public string GetColorString()
=> string.Format("R={0} G={1} B={2}", Color.Red, Color.Green, Color.Blue);
}Refined Abstraction
csharp
// Refined abstraction — extends Shape without knowing which Color is in use.
public class Square : Shape
{
public Square(Color color) : base(color) {}
public override string ToString()
=> quot;Square color: {GetColorString()}";
}
// Usage — color and shape vary independently; adding a new color or shape
// means adding a new class only, not modifying existing ones.
Color yellow = new ColorYellow();
Shape square = new Square(yellow);
Console.WriteLine(square); // Square color: R=255 G=255 B=0