Dot Net For All

Bridge Pattern with C# example

In this article I will discuss about the bridge pattern in C# with practical example. Bridge pattern is also an structural pattern like Proxy and decorator patterns.

You may read other articles in this series at below links.

  1. Proxy pattern 
  2. Decorator pattern
  3. SOLID principles

What is Bridge Pattern?

A bridge pattern in used to decouple abstraction from its implementation enabling them to vary independently. This is the pattern which helps the clients to maintain the versioning of the software. If a new version of the software is released it should not break the older clients functionalities. There is no need to change the client code for adhering to the newer version. But the client need to specify which version it has to use.

Practical Example of Bridge Pattern

Lets see what happens if I am not using the Bridge pattern in my application.

Problem:

Myself begin an avid reader, I have developed an reader App which is supported by various windows versions.

Lets check the code first and I will explain it later.

public class ReadingApp
    {
        public string Text { get; set; }

        public virtual void Display()
        {
            Console.WriteLine(Text);
        }

        public virtual void ReverseDisplay()
        {
            Console.WriteLine(new String(text.Reverse().ToArray()));
        }
    }

    public class Windows8App:ReadingApp
    {
        public override void Display()
        {
            Console.WriteLine("Display in windows 8");
            base.Display(); 
        }

        public override void ReverseDisplay()
        {
            Console.WriteLine("Reverse display in windows 8".Reverse());
            base.ReverseDisplay();
        }
    }

    public class Windows10App : ReadingApp
    {
        public override void Display()
        {
            Console.WriteLine("Display in windows 10");
            base.Display();
        }

        public override void ReverseDisplay()
        {
            Console.WriteLine("Reverse display in windows 10".Reverse());
            base.ReverseDisplay();
        }
    }

 static void Main(string[] args)
 {
     ReadingApp readingApp = new Windows10App() { Text = "Read this text" };
     readingApp.Display();

     ReadingApp readingAppon8 = new Windows8App() { Text = "Read this text" };
     readingAppon8.Display();

     Console.Read();
 }

I have developed an ReadingApp class. First version of the class only supported the Display() method. This method will only display the the text as it is. The class is implemented and modified with some code in Windows8 and Windows10 platforms.

Now with the new version of the class I want the reader to read the text in front of the mirror. For the same reason I will include a new method into the class named ReverseDisplay().

Now to read the reverse text in front of the mirror I need to do lot of changes at the client side. Also If I want to change any of the method I have to change all the classes. Suppose I want to shown only a word per row. I have to do the desired change at each class.

Solution:

To overcome the disadvantages such scenarios bridge pattern comes to the rescue. Lets refactor the classes to achieve more decoupled code. This should help us to change the abstractions independently. Lets check the code in below snippet.

public abstract class ReadingApp
    {
        protected IDisplayFormatter displayformatter;
        public ReadingApp(IDisplayFormatter displayformatter)
        {
            this.displayformatter = displayformatter;
        }

        public string Text { get; set; }
        public abstract void Display();        
    }

    public class Windows8App : ReadingApp
    {
        public Windows8App(IDisplayFormatter displayFormatter) : base(displayFormatter)
        {
        }

        public override void Display()
        {
            displayformatter.Display("This is for Windows8\n" + Text);
        }
    }

    public class Windows10App : ReadingApp
    {
        public Windows10App(IDisplayFormatter displayFormatter) : base(displayFormatter)
        {
        }

        public override void Display()
        {
            displayformatter.Display("This is for Windows10\n" + Text);
        }
    }

    public interface IDisplayFormatter
    {
        void Display(string text);
    }

    public class NormalDisplay : IDisplayFormatter
    {
        public void Display(string text)
        {
            Console.WriteLine(text);
        }
    }

    public class ReverseDisplay : IDisplayFormatter
    {
        public void Display(string text)
        {
            Console.WriteLine(new String(text.Reverse().ToArray()));
        }
    }

As we can see in the above code. I have abstracted out the display functionality. And the concrete windows 8 and windows 10 class implement the Reading App. The implementation of the Display method is totally independent  of the abstraction. To call any of the implementation of the display method there are not many changes done on the client side as well.

Check the client code below.

           ReadingApp readingApp = new Windows10App(new NormalDisplay()) { Text = "Read this text" };
            readingApp.Display();

            ReadingApp readingAppon8 = new Windows8App(new NormalDisplay()) { Text = "Read this text" };
            readingAppon8.Display();

            ReadingApp readingAppR = new Windows10App(new ReverseDisplay()) { Text = "Read this text" };
            readingAppR.Display();

            ReadingApp readingAppon8R = new Windows8App(new ReverseDisplay()) { Text = "Read this text" };
            readingAppon8R.Display();

            Console.Read();

As you can see in the code above I just need to provide the correct formatter at the run time to get the correct display.

To implement the bridge pattern we need to identify the operations that are not always implemented in the same way.

Also we should implement the bridge pattern when we want to

Conclusion:

In this article I have discussed about the bridge pattern with a simple C# code example. This should help you to understand how implementation can be separated from abstraction.

Top career enhancing courses you can't miss

My Learning Resource

Excel your system design interview