Bridge Design Pattern in C#

Bridge Design Pattern in C# with Examples

In this article, I am going to discuss the Bridge Design Pattern in C# with Examples. Please read our previous article where we discussed the Decorator Design Pattern in C# with Examples. The Bridge Design Pattern falls under the category of Structural Design Pattern. As part of this article, we are going to discuss the following pointers.

  1. What is the Bridge Design Pattern in C#?
  2. Understanding Abstraction and Implementation in Detail.
  3. Understanding the Bridge Design Pattern in C# with Real-Time Examples.
  4. Implementation of the Bridge Design Pattern in C#.
  5. Understanding the Class Diagram of the Bridge Design Pattern.
  6. When do we need to use the Bridge Design Pattern in Real-Time Applications?
What is Bridge Design Pattern in C#?

As per the Gang of Four definitions, the Bridge Design Pattern “Decouples an abstraction from its implementation so that the two can vary independently“.

In the Bridge Design Pattern, there are 2 parts. The first part is the Abstraction and the second part is the Implementation. The Bridge Design Pattern allows both Abstraction and Implementation to be developed independently and the client code can only access the Abstraction part without being concerned about the Implementation part.

The Bridge Design Pattern separates the Abstraction hierarchy and the Implementation hierarchy into two different layers so that change in one Hierarchy will not affect the development or functionality of another Hierarchy. If this is not clear at the moment, then don’t worry, we will explain this with one Real-Time Example.

Note: We know the Concept of Inheritance where we specify different implementations of an abstraction. But with Inheritance, implementations are tightly bound with the abstraction and cannot be modified independently. The Bridge Design Pattern provides an alternative approach to inheritance when we can have more than one version of the abstraction.

Understanding the Definition of Bridge Design Pattern:

In order to understand the definition of a Bridge Design Pattern, please have a look at the following image. Suppose we have one requirement to SAVE or DELETE an object in the persistence. Here, we can save the object either into a File System or into a Database. In the same way, we can also delete an object either from a File System or from a Database. So, on the right-hand side, you can see two implementers. The FileSystemPersistenceImplementor is used to save the object into a file whereas the DatabasePersistenceImplementor is used to save the object into a database. In the middle, you can see the Abstraction Layer which provides two methods to do the Save and Delete Operations. Now, the client will call the Abstraction Layer method and the abstraction layer will use one of the Persistence implementations to do the operation. So, here, the client is not worried about the Implementation.

What is Bridge Design Pattern in C#?

So, as per the Bridge Design Pattern, the Abstraction and Implementation should be in separate layers. Here, Persistence is the Abstraction Layer and Persistence Implementation is the Implementation Layer. Now, if you want to add a new implementation or if you want to remove any of the existing implementations, then it will not affect the Abstraction Layer. This is the advantage of the Bridge Design Pattern.

The Abstraction Persistence Layer will use any of the Implementers to SAVE or DELETE an object and the client will only use the Abstraction Layer to SAVE or DELETE the object. Now if you read the definitions then you can easily understand the Bridge Design Pattern.

Real-Time Example of Bridge Design Pattern in C#:

In the Bridge Design Pattern, there are two layers. The first layer is the Abstraction Layer and the second layer is the Implementation Layer. If we do make any changes in the Implementation Layer, then it won’t affect the Abstraction Layer. Similarly, if we made any changes in the Abstraction Layer, then it won’t affect the Implementation layer.

Please have a look at the following image for a better understanding of the Bridge Design Pattern. On the left-hand side, you can see the Abstraction. Suppose, you want to turn on the TV or turn off the TV, then what you can do here is, you can use the Remote Control to turn On/Off the TV. The Implementation will be done by the original TV implementer. So, in this case, Samsung TV or Sony TV will implement the turn On or turn Off functionality. So, the abstraction will use one of the implementers to turn on or turn off the TV.

Real-time Example of Bridge Design Pattern in C#

Suppose, later you want to add a new implementation then you can do this in the Implementation Layer. For example, you can add new TV (for example Panasonic TV) in the Implementation Layer which will not affect the Abstraction Layer. You can also add a new Panasonic TV Remote Control in the Abstraction Layer without affecting the Implementation Layer. So, this is one of the best examples of the Bridge Design Pattern.

Note: First we will implement the Bridge Design Pattern example using C# and then we will try to understand the Class Diagram or UML Diagram of the Bridge Design Pattern by comparing it with our Example.

Implementation of Bridge Design Pattern using C#:

Let us implement the above example step by step using the Bridge Design Pattern in C#.

Step 1: Creating Abstract LED TV

Create an interface with the name ILEDTV.cs and then copy and paste the following code into it. This interface has three methods (SwitchOff, SwitchOn, and SetChannel). This interface will be implemented by the implementation classes. This Interface acts as a bridge between the abstraction classes and implementor classes. This Interface defines the operations for all implementation classes.

namespace BridgeDesignPattern
{
    // This is going to be an interface that acts as a bridge between the abstraction classes and implementer classes
    // The Implementor Interface defines the operations for all implementation classes.
    // It doesn't have to match the Abstraction's interface. 
    // In fact, the two interfaces can be entirely different. 
    
    public interface ILEDTV
    {
        void SwitchOn();
        void SwitchOff();
        void SetChannel(int channelNumber);
    }
}
Step 2: Creating Concrete LED TV

In our example, we are going to create two concrete classes i.e. SamsungLedTv and SonyLedTV. These are going to be classes that implement the ILEDTV interface and also provide the implementation details for the associated Abstraction class. Each Concrete Implementation corresponds to a specific platform.

SamsungLedTv

Create a class file with the name SamsungLedTv.cs and then copy and paste the following code into it. This class implements the LEDTV interface and provides implementations for SwitchOn, SwitchOff, and SetChannel methods. Using the SwitchOn method we can turn On the Samsung TV. Using the SwitchOff method we can turn Off the Samsung TV and using the SetChannel method we can change the channel number of the Samsung TV.

using System;
namespace BridgeDesignPattern
{
    // This is going to be a class which implements the ILEDTV interface and 
    // also provide the implementation details for the associated Abstraction class.
    // Each Concrete Implementation corresponds to a specific platform
    
    public class SamsungLedTv : ILEDTV
    {
        public void SwitchOn()
        {
            Console.WriteLine("Turning ON : Samsung TV");
        }
        public void SwitchOff()
        {
            Console.WriteLine("Turning OFF : Samsung TV");
        }

        public void SetChannel(int channelNumber)
        {
            Console.WriteLine("Setting channel Number " + channelNumber + " on Samsung TV");
        }
    }
}
SonyLedTv:

Create a class file with the name SonyLedTv.cs and then copy and paste the following code into it. This class also implements the ILEDTV interface and also provides implementations for SwitchOn, SwitchOff, and SetChannel methods. Using the SwitchOn method we can turn On the Sony TV. Using the SwitchOff method we can turn Off the Sony TV and using the SetChannel method we can change the channel number of the Sony TV.

using System;
namespace BridgeDesignPattern
{
    // Each Concrete Implementation corresponds to a specific platform
    // This is going to be a class and should implement the Implementation interface
    public class SonyLedTv : ILEDTV
    {
        public void SwitchOn()
        {
            Console.WriteLine("Turning ON : Sony TV");
        }
        public void SwitchOff()
        {
            Console.WriteLine("Turning OFF : Sony TV");
        }

        public void SetChannel(int channelNumber)
        {
            Console.WriteLine("Setting channel Number " + channelNumber + " on Sony TV");
        }
    }
}
Step 3: Creating Abstract Remote Control

Create a class with the name AbstractRemoteControl.cs and then copy and paste the following code into it. This is going to be an abstract class having three abstract methods (SwitchOn, SwitchOff, and SetChannel). Here, you can give the method names the same as the ILEDTV interface or you can also give different names. It has one protected variable ledTv which is going to be available to subclasses. 

namespace BridgeDesignPattern
{
    //This is an abstract class that contains members that define an abstract business object and its functionality.
    //It contains a reference to an object of type ILEDTV and delegates all of the real work to this object.
    //It can also act as the base class for other abstractions.
    
    public abstract class AbstractRemoteControl
    {
        protected ILEDTV ledTv;
        public abstract void SwitchOn();
        public abstract void SwitchOff();
        public abstract void SetChannel(int channelNumber);
    }
}
Step 4: Creating Concrete Remote Control

Here, we are going to create two concrete remote control classes i.e. SamsungRemoteControl and SonyRemoteControl

SamsungRemoteControl:

Create a class file with the name SamsungRemoteControl.cs and then copy and paste the following code into it. This is a concrete class and it implements the abstract AbstractRemoteControl class and provides the implementation for SwitchOn, SwitchOff, and SetChannel methods. Further, if you notice, the constructor takes one parameter of ILEDTV type i.e. an instance of one of the child classes of ILEDTV type which we want to access remotely. Further, we are passing that ILEDTV object to the base class constructor.

namespace BridgeDesignPattern
{
    // This is going to be a concrete class which inherits from the Abstraction class i.e. AbstractRemoteControl. 
    // This Redefined Abstraction Class extends the interface defined by AbstractRemoteControl class.
    public class SamsungRemoteControl : AbstractRemoteControl
    {
        public SamsungRemoteControl(ILEDTV ledTv) 
        {
            this.ledTv = ledTv;
        }

        public override void SwitchOn()
        {
            ledTv.SwitchOn();
        }

        public override void SwitchOff()
        {
            ledTv.SwitchOff();
        }

        public override void SetChannel(int channelNumber)
        {
            ledTv.SetChannel(channelNumber);
        }
    }
}
SonyRemoteControl:

Create a class file with the name SonyRemoteControl.cs and then copy and paste the following code into it. This is also going to be a concrete class and also implements the AbstractRemoteControl class and provides the implementation for SwitchOn, SwitchOff, and SetChannel methods. Further, if you notice, the constructor takes one parameter of ILEDTV type i.e. an instance of one of the child classes of ILEDTV type which we want to access remotely. Further, we are passing that ILEDTV object to the base class constructor.

namespace BridgeDesignPattern
{
    // This is going to be a concrete class which inherits from the Abstraction class i.e. AbstractRemoteControl. 
    // This Redefined Abstraction Class extends the interface defined by AbstractRemoteControl class.
    public class SonyRemoteControl : AbstractRemoteControl
    {
        public SonyRemoteControl(ILEDTV ledTv)
        {
            this.ledTv = ledTv;
        }

        public override void SwitchOn()
        {
            ledTv.SwitchOn();
        }

        public override void SwitchOff()
        {
            ledTv.SwitchOff();
        }

        public override void SetChannel(int channelNumber)
        {
            ledTv.SetChannel(channelNumber);
        }
    }
}
Step5: Client Class

In our example, the Main method of the Program class is going to be the Client Code. So, please modify the Main method of the Program class as shown below. Here, first, we are using the SonyRemoteControl and attaching the SonyLedTv so that we can access Sony Led TV remotely (i.e. Turn On, Change Channel, and Turn Off). We can also do the same thing using SamsungRemoteControl to access SansungLedTv remotely.

using System;
namespace BridgeDesignPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            // Except for the initialization phase, where an Abstraction object gets i.e. SonyRemoteControl or SamsungRemoteControl
            // linked with a specific Implementation object i.e. new SonyLedTv() or new SamsungLedTv(), 
            // the client code should only depend on the Abstraction class i.e. SonyRemoteControl or SamsungRemoteControl. 
            AbstractRemoteControl sonyRemoteControl = new SonyRemoteControl(new SonyLedTv());
            sonyRemoteControl.SwitchOn();
            sonyRemoteControl.SetChannel(101);
            sonyRemoteControl.SwitchOff();

            Console.WriteLine();

            AbstractRemoteControl samsungRemoteControl = new SamsungRemoteControl(new SamsungLedTv());
            samsungRemoteControl.SwitchOn();
            samsungRemoteControl.SetChannel(202);
            samsungRemoteControl.SwitchOff();

            Console.ReadKey();
        }
    }
}
Output:

Implementation of Bridge Design Pattern in C#

Now, I hope you understand How to Implement the Bridge Design Pattern in C#. So, let us try to understand the Class Diagram or UML Diagram and understand the different components or participants involved in the Bridge Design Pattern.

Understanding the Class Diagram or UML Diagram of Bridge Design Pattern:

Please have a look at the following image to understand the class diagram or UML Diagram of the Bridge Design Pattern in C#.

Class Diagram or UML Diagram of Bridge Design Pattern

As shown in the above image, the bridge design pattern consists of four participants. They are as follows.

  1. Implementer: This is an interface and this interface must be implemented by all the implementation classes. This interface is going to act as a bridge between the abstraction classes and the implementer classes. In our example, it is the ILEDTV interface.
  2. ConcreteImplementationA / ConcreteImplementaionB: These are going to be classes and implement the Implementor (ILEDTV) interface. In our example, it is our SamsungLedTv and SonyLedTv classes. These classes contain the concrete implementation of all the operations (in our example implementation for SwitchOn, SwitchOff, and SetChannel methods).
  3. Abstraction: This is going to be an abstract class. In our example, it is the AbstractRemoteControl class. It defines the methods (in our example SwitchOn, SwitchOff, and SetChannel) for the Client Code to call. The protected implementer variable (in our example it is the ledTv variable) holds a reference to the object that performs the implementation.
  4. ConcreteAbstraction / RefinedAbstraction: ConcreteAbstractions are the concrete classes that are inherited from the Abstraction abstract class. In our example, it is the SamsungRemoteControl and SonyRemoteControl.
When do we need to use Bridge Design Pattern in C# Real-Time Applications?

We need to use the Bridge Design Pattern in C# Real-Time Applications, when

  1. We want to hide the implementation details from the client.
  2. We want the selection or switching of the implementation to be at runtime rather than design time.
  3. We want both the abstraction and implementation classes to be extensible by the subclasses.
  4. We want to avoid a tight coupling binding between an abstraction and its implementation. 
  5. The changes in the implementation of an abstraction should have no impact on clients.
  6. When we want to share an implementation among multiple objects and this should be hidden from the client.  

In the next article, I am going to discuss Real-Time Examples of Bridge Design Patterns using C#- Send Messages. Here, in this article, I try to explain the Bridge Design Pattern in C# with Examples. I hope you understood the need and use of the Bridge Design Pattern in C# with Examples.

2 thoughts on “Bridge Design Pattern in C#”

  1. blank

    why didn’t you use a single class with name “RemoteControl” instead of “SamsungRemoteControl” and “SonyRemoteControl”?
    They work same as each other and in constructor you are sending “LEDTV” to the class. You can use it for calling related methods.

    1. blank

      The names of them are the same, but they are different.
      In other words, there are two different methods with different full names. See below:

      samsungRemoteControl.SwitchOn() => “Turning ON : Samsung TV”
      sonyRemoteControl.SwitchOn() => “Turning ON : Sony TV”

      If you want to implement them with one class “LEDTV”, you need to change the code of it, whenever you add a new brand. Why is it bad? Go below :
      https://dotnettutorials.net/lesson/open-closed-principle/

Leave a Reply

Your email address will not be published. Required fields are marked *