Wednesday, August 12, 2009

Bridge pattern in C#



Intent


The Bridge pattern is used for decoupling an abstraction from its implementation so that both of them can vary independently.

Non-Software Example:

A household switch controlling lights, ceiling fans, etc. is an example of the Bridge. The purpose of the switch is to turn a device on or off. The actual switch can be implemented as a pull chain, simple two-position switch, or a variety of dimmer switches



Benefits:

With bridge pattern the interface and implementation details are decoupled, which means that the implementation of the abstraction (Switches in our example) is often done at run time. So with the given scenario the selection of type of switch whether “pull chain switch” , “two position switch” can be delayed until the switch is actually wired.




The above diagram shows the UML of the Bridge pattern. Below is the explanation of for the UML

Abstraction: The abstraction class acts as a base class for redefined abstractions. Objects of this type hold a reference to the particular implementation that they are using for platform-specific functions. You may find this little difficult to understand, but as you move on you relate the example to this it will be clear.

RefinedAbstraction: Many redefined abstraction may inherit from the abstraction. Each of these inherited classes will have their own very specific implementation.

ImplementationBase: This is the base class for the concrete implementation. This class can be an interface. This class does will not be having Implementation and also shares a relation with Abstraction class.

ConcreteImplementation: The concrete Implementation inherits from the Implementation base. This can be different for different clients.

Once we relate the above diagram with the software example below thing will be clearer.

Software Example & Explanation of Code:

A software example for Bridge pattern would be a system sending messages. The system has an option to either send the messages through email, web service or through MSMQ. When we are asked to design a system like we can think of one base class “MessageSenderBase” and three other classes like “EmailSender”, “MSMQSender” and “WebServiceSender” classes. Like factory pattern we can give the option to the client (lets say a windows client) to instantiate an object of any of the derived classes and instantiate the derive class accordingly. This will work fine.

Let us say that the requirement changed and we need to support the mail sending components for UNIX also. Now with the above implementation we will have to add new classes and make all the changes in the client, derived classes etc. Now let us look at the implementing the same with bridge pattern. Below is the UML for this




Let us define the above classes one by one. Let us start with the “MessageSenderBase” Class. If you compare the pervious UML this would be the Abstract class. Below is the cod for “MessageSenderBase”

MessageSenderBase.cs

namespace BridgePatternConsole
{
public abstract class MessageSenderBase
{
public abstract void SendMessage(string title, string details, string importance);
}
}

The classes which implements the “MessageSenderBase” are “EmailSender”, “WerserviceSender” and the “MSMQSender”. If you compare these classes it will become equivalent to “RefinedAbstraction” of above previous UML. Below are the code snippet for all the


EmailSender.cs

namespace BridgePatternConsole
{
public class EmailSender : MessageSenderBase
{
public override void SendMessage(string title, string details, string importance)
{
Console.WriteLine("Webservice Message " + "Title-->" + title + " Details-->" + details + " Importance-->" + importance); }
}
}

MSMQSender.cs

namespace BridgePatternConsole
{
public class MSMQSender : MessageSenderBase
{
public override void SendMessage(string title, string details, string importance)
{
Console.WriteLine("Webservice Message " + "Title-->" + title + " Details-->" + details + " Importance-->" + importance);
}
}
}

WebserviceSender.cs

namespace BridgePatternConsole
{
public class WebserviceSender : MessageSenderBase
{
public override void SendMessage(string title, string details, string importance)
{
Console.WriteLine("Webservice Message " + "Title-->" + title + " Details-->" + details + " Importance-->" + importance);
}
}
}


Next is the Message Class. This is equivalent to “ImplementationBase” class of the previous UML. This class does not have any implementation. This has three properties “title”, ”Details” and “Importance”. This also has a fourth property which holds a reference to an implementation object. The class will also include a “Send” Method that calls “SendMessage” of the referenced class. Below is the code for the class

Message.cs

namespace BridgePatternConsole
{
public class Message
{
public string Title
{get; set;}

public string Body
{ get; set; }

public string Importance
{ get; set; }

public MessageSenderBase MessageSender
{ get; set; }

public virtual void Send()
{
MessageSender.SendMessage(Title, Body, Importance);
}
}
}


Finally the subclass for the Message that has an additional property. The equivalent class for this in the previous UML is “ConcreteImplementation” This property can be use to provide additional information to the user. The class is specific to windows message sender. The benefit is that when there is a change where we want the UNIX client to speak to the same that also can be achieved here. Below is the code for the

WindowsMessager.CS

namespace BridgePatternConsole
{
public class WindowsMessager : Message
{
public string WindowsComments { get; set;}
public override void Send()
{
string strCustomString = "This is from Windows" + WindowsComments;
MessageSender.SendMessage(Title, strCustomString, Importance);
}
}
}

Now we need a client to run the application. Create a console class and put the below code

MessageSenderBase objEmail = new EmailSender();
MessageSenderBase objMSMQ = new MSMQSender();
MessageSenderBase objWebService = new WebserviceSender();

Message objMessage = new Message();
objMessage.Title = "Message Title";
objMessage.Body = "Message Body";
objMessage.Importance = "Low";

objMessage.MessageSender = objEmail;
objMessage.Send();

objMessage.MessageSender = objMSMQ;
objMessage.Send();

objMessage.MessageSender = objWebService;
objMessage.Send();


WindowsMessager objWindows = new WindowsMessager();
objWindows.Title = "New Message";
objWindows.Body = "Message Body";
objWindows.Importance = "high";
objWindows.WindowsComments = "Test Comments";

objWindows.MessageSender = objEmail;
objWindows.WindowsComments = "Additional Windows Comments";
objWindows.Send();
Console.ReadLine();




Output of the class would look like

Webservice Message
Title-->Message Title Details-->Message Body Importance-->Low
Webservice Message
Title-->Message Title Details-->Message Body Importance-->Low
Webservice Message
Title-->Message Title Details-->Message Body Importance-->Low
Webservice Message
Title-->New Message Details-->This is from Windows Additional Windows Comments
Importance-->high

1 comment:

Anonymous said...

Sorry, this is very old post, but I have one question: Is this pattern similar with DI (Dependency Injection) - injection via property. Thank you for the great explanation of Bridge pattern.