Summary: in this tutorial, you’ll learn about the C# Bridge pattern that decouples an abstraction from its implementation so that the two can vary independently.
Introduction to the C# Bridge pattern
By definition, a Bridge pattern allows you to decouple an abstraction from its implementation so that you can change the two independently.
Suppose you have the following shape class hierarchy:
To make both triangles and rectangles rounded and sketched, you may end up with the subclasses of the Triangle
and Rectangle
classes like this:
But this approach is not flexible because inheritance binds a style (implementation) to a shape (abstraction) permanently.
For example, if you want to add a new shape like a pentagon, you need to define three classes Pentagon
, RoundedPentagon
, and SketchedPentagon
.
Additionally, if you want to add a more shape style like embossed, you need to add a new class to each shape, which does not scale well.
To solve this problem, you can use the Bridge pattern to separate the style from the shape hierarchy like this:
C# Bridge pattern implementation
The following program illustrates the bridge pattern:
using static System.Console;
namespace BridgePattern;
public abstract class Style
{
public abstract void Decorate();
}
public class RoundedStyle : Style
{
public override void Decorate() => WriteLine("rounded.");
}
public class SketchedStyle : Style
{
public override void Decorate() => WriteLine("sketched.");
}
public abstract class Shape
{
protected Style Style;
public Shape(Style style)
{
Style = style;
}
public abstract void ApplyStyle();
}
public class Triangle : Shape
{
public Triangle(Style style) : base(style)
{
}
public override void ApplyStyle()
{
Write("Make the triangle ");
Style.Decorate();
}
}
public class Rectangle : Shape
{
public Rectangle(Style style) : base(style)
{
}
public override void ApplyStyle()
{
Write("Make the rectangle ");
Style.Decorate();
}
}
public class Program
{
public static void Main(string[] args)
{
var triangle = new Triangle(new SketchedStyle());
triangle.ApplyStyle();
var rectangle = new Rectangle(new RoundedStyle());
rectangle.ApplyStyle();
}
}
Code language: C# (cs)
Output:
Make the triangle sketched.
Make the rectangle rounded.
How it works.
First, define the Style
abstract class that has the Decorate()
abstract method:
public abstract class Style
{
public abstract void Decorate();
}
Code language: C# (cs)
Second, define the RoundedStyle
class that inherits from the Style
class. The Decorate()
method displays the " rounded."
message to the Console:
public class RoundedStyle : Style
{
public override void Decorate() => WriteLine("rounded.");
}
Code language: C# (cs)
Third, define the SketchedStyle
class that also inherits from the Style
class. The Decorate()
method shows the " sketched."
message to the Console:
public class SketchedStyle : Style
{
public override void Decorate() => WriteLine("sketched.");
}
Code language: C# (cs)
Fourth, define the Shape
abstract class that has a Style
object as a property and an abstract method ApplyStyle()
that calls the Decorate()
method of the Style
object to set the style for shape:
public abstract class Shape
{
protected Style Style;
public Shape(Style style)
{
Style = style;
}
public abstract void ApplyStyle();
}
Code language: C# (cs)
Fifth, define the Triangle
class that extends the Shape
class. The ApplyStyle()
method writes a message to the console and calls the Decorate()
method of the style object:
public class Triangle : Shape
{
public Triangle(Style style) : base(style)
{
}
public override void ApplyStyle()
{
Write("Make the triangle ");
Style.Decorate();
}
}
Code language: C# (cs)
Sixth, define the Rectangle
class that inherits from the Shape
class. The ApplyStyle()
method also writes a message to the console and calls the Decorate()
method of the Style
object:
public class Rectangle : Shape
{
public Rectangle(Style style) : base(style)
{
}
public override void ApplyStyle()
{
Write("Make the rectangle ");
Style.Decorate();
}
}
Code language: C# (cs)
Finally, create an instance of the Triangle
class with the SketchedStyle
and calls the
method to set its style to sketch. Similarly, create an instance of the ApplyStyle()
Rectangle
class and calls the
method to set its style to rounded.ApplyStyle()
public class Program
{
public static void Main(string[] args)
{
var triangle = new Triangle(new SketchedStyle());
triangle.ApplyStyle();
var rectangle = new Rectangle(new RoundedStyle());
rectangle.ApplyStyle();
}
}
Code language: C# (cs)
Summary
- Use the C# Bridge pattern to decouple an abstraction from its implementation so that the two can vary independently.