C# Design Patterns: Bridge

Biswajit Sahoo
5 min readJun 4, 2023

--

Bridge C# Design Pattern

Thanks for visiting this article. Please scroll down for the bite-sized explanation of this pattern.

Definition

The Bridge Pattern is a structural design pattern, that decouples an abstraction from its implementation, allowing each to vary independently.

The bridge pattern is a fundamental yet powerful design pattern necessary for almost all of the code you’ll write, to achieve decoupling and flexibility. Therefore, having a good understanding of what issue this solves, will help you write better code.

Where to use?

It is useful in scenarios where multiple variations of an abstraction exist and any change to the abstraction has to be implemented in each of the implementations.

Example

Consider, having a game where we have two types of NPCs (non-player characters) i.e. Warriors & Archers derived from an abstract class Character.

The Character class provided a Move() & Attack(), to allow overrides of movement and attack for the derived character types.

Note: The code examples may or may not have syntax, or compilation errors, and are for representational purposes only

Abstract Character base class with Move() and Attack()

And the concrete abstractions for Warriors & Archers implement the overrides from Character

Note: The code examples may or may not have syntax, or compilation errors, and are for representational purposes only

Warrior implementing Character
Archer implementing Character

Now we wanted to implement another NPC in the game for trading valuable items as a Merchant, deriving from Character.

Note: The code examples may or may not have syntax, or compilation errors, and are for representational purposes only

Merchant implementing abstracted method Attack(), which is not needed for this character type

The Merchant needs to inherit the Character to Move(), but the merchant cannot attack, it can Trade().

🤔 You could already see the problem here, we cannot extend implementations independently from the abstraction i.e. Character.

What we need is the decoupling between the abstraction and its implementation. And this is the exact issue, the Bridge design pattern helps in solving.

Implementing the Bridge Pattern

In order to implement the bridge pattern, we first need to identify the varying abstractions that we can group behind an interface. And according to our example above they are Attack() and Trade().

These are the two behaviours, our current NPCs perform when they interact with the Player, & let’s call the interface IInteractionBehaviour, that’ll have only one method Interact() to implement by the behaviours.

Note: The code examples may or may not have syntax, or compilation errors, and are for representational purposes only

IInteractionBehaviour as the bridge implementor

We will isolate the behaviours into their own class implementing the IInteractionBehaviour interface i.e., AttackBehaviour and TradeBehaviour

Note: The code examples may or may not have syntax, or compilation errors, and are for representational purposes only

AttackBehaviour is a concrete implementor of type IInteractionBehaviour
TradeBehaviour is a concrete implementor of type IInteractionBehaviour

In order to bridge the implementor (IInteractionBehaviour) with the abstraction (Character), we will modify the Character to hold a reference to the implementor and call the behaviour upon interaction.

Note: The code examples may or may not have syntax, or compilation errors, and are for representational purposes only

Abstraction Character, holding a reference to the Implementor and calls the behaviour upon Interaction

Now, our derived characters Warrior, Archer and Merchant can initialize their individual behaviours, while keeping the same abstraction

Note: The code examples may or may not have syntax, or compilation errors, and are for representational purposes only

Warrior initialized with the behaviour type
Archer initialized with the behaviour type
Archer initialized with the behaviour type

With all of it in place, our main Game.cs would look like this 👇

Note: The code examples may or may not have syntax, or compilation errors, and are for representational purposes only

Game class handling NPCs interactions with the Player, each behaving differently using the Bridge Pattern

And that’s how the Bridge pattern can be used to allow the abstracted implementations i.e. Warrior, Archer and Merchant, to vary independently from the abstraction i.e. Character.

What else?

There are some identifiers for Bridge Pattern, I have seen, other blogs using, and I wanted to refer to them last, for anyone to be able to link them with the example for understanding them better 😃

  • Abstraction — (Character.cs)This represents the high-level abstraction that clients (Game.cs) interact with. It defines the interface or abstract class that clients use to access the functionality provided by the implementation. The abstraction typically contains a reference to the implementation.
  • Implementor — (IInteractionBehaviour.cs) — This represents the interface or abstract class that defines the operations that the abstraction can perform. It provides a set of methods or properties that represent the implementation-specific behaviour.
  • Concrete Abstraction — (Warrior.cs, Archer.cs & Merchant.cs) — These are the concrete classes that extend the abstraction. They provide specific implementations of the high-level abstraction using the Implementor interface. Concrete abstractions can add additional methods or properties specific to their needs.
  • Concrete Implementor — (AttackBehaviour.cs & TradeBehaviour.cs) — These are the concrete classes that implement the Implementor interface. They provide the actual implementation of the operations defined by the Implementor interface.

And that’s all to it. To summarize, the Bridge Pattern promotes loose coupling between the abstraction and its implementation, allowing us to change and extend both independently.

Hope this helped with giving you some clarity on how this pattern can be implemented and used in a real-world scenario.

On the last note. If you like the article please do like and share, and also feel free to provide your valuable comments and feedback.

--

--

Biswajit Sahoo

Professional XR Developer and Gamer. Writes about system designs, and design patterns in C#.