I am here to continue the discussion around Design Patterns. Before starting with Part 11, let's first look at the previous articles of the series.
Today we will go through one of the structural design patterns called Bridge. Before talking about its implementation let’s begin with defining it.
As per GOF guys, Bridge Pattern is defined as follows.
“Decouple an abstraction from its implementation so that the two can vary independently.”
Well! Let’s understand what they mean and where this pattern can fit into.
In a case when there is more than one version of abstract methods and also many ways to implement them then providing brand new concrete classes of each abstract version may end up with lots of classes. Bridge pattern addresssethe same problem by introducing an interface which works as a bridge between abstract and concreate classes.
Below is the UML for Bridge pattern.
Bridge pattern has four key elements as in the following.
- Abstraction - Client facing class. Keeps the reference of an object of type Implementor.
- RefinedAbstraction - Extends the Abstraction class to have multiple version of abstract methods.
- Implementor or Bridge - This interface acts as bridge between an abstraction classes and concreate implementation classes.
- ConcreteImplementor -This class implements the Implementor interface.
How Bridge Pattern works
We will understand this by simple example.
Let’s assume a scenario when you have couple of types of email to send and have several ways to do it and at the same time, you want to give choice to client to choose the specific type of email and way or method to send it.
This is the perfect example where bridge pattern can be fit as it allows variation of source (or abstract methods) and target (concreate implementations).
Let’s begin the illustration by creating bridge or Implementor interface.
-
-
-
- public interface IEmailSender
-
- {
- void SendEmail(string subject, string body);
- }
And then the abstract class which defines the business objects and methods as in the following.
-
-
-
- public abstract class Email
- {
- public IEmailSenderMessageSender
- {
- get;
- set;
- }
-
- public string Subject {
- get;
- set;
- }
-
- public string Body {
- get;
- set;
- }
-
- public abstract void Send();
-
- }
As you can see Email class is holding the reference of IEmailSender to be able to call the appropriate concreate Implementor at runtime.
Now let’s create the RefinedAbstraction classes which are used to support the multiple versions of abstract methods. Here we have two types of abstractions i.e. SystemEmail and UserEmail.
-
-
-
- public class SystemEmail: Email
- {
- public override void Send()
- {
- string emailSubject = string.Format("Subject: {0} from System", Subject);
- string emailBody = string.Format("Email Body:\n{0}", Body);
- MessageSender.SendEmail(emailSubject, emailBody);
-
- }
-
- }
-
-
-
-
-
-
-
- public class UserEmail: Email
- {
- publicoverridevoid Send()
- {
- stringemailSubject = string.Format("Subject: {0} from User", Subject);
-
- stringemailBody = string.Format("Email Body:\n{0}", Body);
-
- MessageSender.SendEmail(emailSubject, emailBody);
- }
- }
And here comes the concrete implementation classes. These classes support the idea of multiple targets.
-
-
-
- public class WebServiceEmailSender: IEmailSender
- {
- publicvoidSendEmail(string subject, string body)
- {
- Console.WriteLine("Sending Email using WebService:\n{0}\n{1}\n", subject, body);
- }
- }
-
-
-
-
-
- public class WCFEmailSender: IEmailSender
- {
- public void SendEmail(string subject, string body)
- {
- Console.WriteLine("Sending Email using WCF:\n{0}\n{1}\n", subject, body);
- }
- }
-
-
-
-
-
-
-
- public class WebAPIEmailSender: IEmailSender
- {
- public void SendEmail(string subject, string body)
- {
- Console.WriteLine("Sending Email using Web API:\n{0}\n{1}\n", subject, body);
- }
- }
As you can see above that we have given three types of concrete implantations to client to choose from.
So at this point, we are done with required setups. Now let’s use that in client and see the action.
- Console.Title = "Bridge pattern demo";
-
- IEmailSenderwebService = newWebServiceEmailSender();
-
- IEmailSenderwcf = newWCFEmailSender();
-
- IEmailSenderwebApi = newWebAPIEmailSender();
-
-
-
- Emailemail = newSystemEmail();
-
- email.Subject = "Test Message";
-
- email.Body = "Hi there, This is a Test Message from System";
-
- email.MessageSender = webService;
-
- email.Send();
-
- email.MessageSender = wcf;
-
- email.Send();
-
- email.MessageSender = webApi;
-
- email.Send();
-
-
-
- email = newUserEmail();
-
- email.Subject = "Test Message";
-
- email.Body = "Hi there, This is a Test Message from Prakash";
-
- email.MessageSender = webApi;
-
- email.Send();
Output
You can see by using Bridge pattern how smoothly the client can select the version of abstract methods (between SystemEmail and UserEmail) and concreate implementations (among WebService, WCF and Web API).
Note:
Sometimes people get confused with the purpose of Bridge pattern with Adapter. Please note that Adapter pattern is used to make two incompatible interfaces to work which are having similar functionality but their method names or return types are different. On the other side, Bridge pattern is used when client needs a choice to select from a variety of abstract methods and concrete implementations and both abstract methods and concrete implementations can be modified independently.
Hope you have liked the article. I leook forward for your comments/suggestions.
Read more articles on Design Patterns: