Continuing with the design patterns topic, today I am going to cover the Adapter Design Pattern. Adapter is a structural design pattern. In my opinion it is one of the most easier to understand and implement as well. Lets get started.
Problem statement
Over the last couple of years there has been a tremendous increase in the number of social networking sites. Facebook, Twitter, Hi5, Linkedin, Orkut are just a few examples of social networking sites that I have used personally. Almost every month there are at least 2-3 others which pop up through my friends lists and some how I manage to keep myself away from joining them (at least for the time being). So lets assume that the organization for which we are working decides to build a next generation social networking application. To start with the organization has decided to build an app which can be used to integrate Twitter and Facebook functionality. Assume we are going to build an app which competes with other social networking clients like TweetDeck or Sesmic Desktop to name a few.
Solution without Adapter pattern
In order to build the app we need access to the API’s from both Twitter as well as Facebook. Note that I am not going to refer to the actual API’s published by Twitter and Facebook. If we do that this demo would become much more complex. To keep things simple I am going to build a set of classes myself which we can assume are the API’s published by the social networking providers.
Lets look at the Twitter API first.
public class TwitterAPI
{
public void Tweet(string tweetText)
{
// actual implementation calls Twitter API
}
}
The TwitterAPI class exposes a method called Tweet which accepts the contents of the Tweet as parameter. Similarly assume that we have access to FacebookAPI which exposes a method named Update as shown below
public class FacebookAPI
{
public void Update(string status)
{
// actual implementation calls Facebook API
}
}
Now lets look at how we can make use of these two API’s in our application.Once again for simplicity I am not going to build the application from scratch. I’ll concentrate on only those parts that are of our interest. So I’ll not build any UI for this application.
Assuming that there is a full blown UI for the application already developed, we can concentrate on the piece of code which will be interfacing with the API’s in updating the status of the user. Here is how our application will call the API
public class SocialNetworkingClient
{
public void UpdateStatus(string status, string targetNetwork)
{
if (targetNetwork == "Facebook")
{
FacebookAPI facebookClient = new FacebookAPI();
facebookClient.Update(status);
}
if (targetNetwork == "Twitter")
{
TwitterAPI twitterClient = new TwitterAPI();
twitterClient.Tweet(status);
}
}
}
We have a method named UpdateStatus which takes two parameters and calls the appropriate social networking provider API.
Twist in the tale
Everything seems to be going on smoothly and as usual the CEO of the company decides to bring all the popular social networks under the radar of this application. Lets say the CEO decided to integrate with LinkedIn as well as Orkut or any other social network of your choice for that matter. And mind you we are not restricted only to these because we know that in future there will be other social networks which will emerge and we will have to support them as well.
Refactored solution with Adapter design pattern
Based on the changed requirements we need to refactor the existing solution to fit the business needs. We can get access to the API’s of the required networks like LinkedIn and Orkut. We can also refactor the code which creates the specific instances of types of API like FacebookAPI, TwitterAPI, OrkutAPI, LinkedinAPI etc into a switch case instead of the if construct.
But if we re-examine the problem at hand, all that we are doing is calling the appropriate method on a particular type of API with a message text to update the status. The basic functionality is the same. Only thing that changes is the type of social networking client and the actual method name which is used to update the status. We can try to unify this step of updating the status and make it common for all the providers which can make our client code simple to develop and maintain.
Since we are dependent on the external vendors or providers like Facebook, twitter etc for their API’s we cannot possibly change the method names and signatures. Since these API’s are used by many other clients its difficult to change the contracts once they are published. How can we overcome this problem?
One of the commonly used technique is to wrap the third party API into our own class. This allows us to have the control over what we have in our source code. We have the liberty to refactor the codebase in our application.So lets start with defining an interface which will be common to all the social networking providers. We can define an abstraction as shown below
public interface ISocialNetworking
{
void UpdateStatus(string message);
}
We have an interface called ISocialNetworking which exposes a method called UpdateStatus with a string parameter. Now we can use this interface for any type of social network including the ones we might have to use in future. You might be tempted to ask how does defining just an interface solves the issue we have at hand. Lets look at the classes which implement this interface.
Since currently Facebook is the most popular social networking site, we try to use this interface with Facebook API. If we look at the FacebookAPI class the method it exposes is named Update. Our ISocialNetworking which tries to unify all the social networks exposes a method called UpdateStatus. In order to make these two methods work in unison we need a class which can implement the ISocialNetworking interface and redirect the call to Facebook’s Update method. Here is how we do it.
public class FacebookAdapter : ISocialNetworking
{
private readonly FacebookAPI _facebookAPI = new FacebookAPI();
public void UpdateStatus(string message)
{
_facebookAPI.Update(message);
}
}
FacebookAdapter implements the ISocialNetworking interface. Upon calling the UpdateStatus method, this class redirects the call to the actual FacebookAPI instance calling the Update method.
Similarly we can implement the TwitterAdapter which redirects the call to TwitterAPI.
public class TwitterAdapter : ISocialNetworking
{
private readonly TwitterAPI _twitterApi = new TwitterAPI();
public void UpdateStatus(string message)
{
_twitterApi.Tweet(message);
}
}
I’ll leave the implementation of OrkutAdapter & LinkedinAdapter to the reader as an exercise to save some space here. Finally we can make use of these classes in our application. The refactored UpdateStatus method takes a much simpler form.
public void UpdateStatus(string status, string targetNetwork)
{
ISocialNetworking socialNetworkingAPI = null;
switch (targetNetwork)
{
case "Facebook":
socialNetworkingAPI = new FacebookAdapter();
break;
case "Twitter":
socialNetworkingAPI = new TwitterAdapter();
break;
}
if (socialNetworkingAPI != null)
{
socialNetworkingAPI.UpdateStatus(status);
}
}
By providing an interface within our application code we ensured that the third party API’s can be adapted to our needs.
Even after refactoring the creational logic from if statements to switch, the above code could cause maintenance problems. You can look at my earlier posts on Factory Pattern and Abstract Factory Pattern to understand how we can make use of these patterns to simply things even further.
Conclusion
Adapter design pattern is very helpful when we don’t have access to other code bases or are dependent on third part interfaces. We can use adapter to make communication possible between incompatible classes. Commonly used terminology within Adapter Design Pattern are the Adapter class itself and the Adaptee. In our example the FacebookAdapter and TwitterAdapter are the adapter implementations. FacebookAPI and TwitterAPI are the adaptee. And finally SocialNetworkingCient class is the client.
Adapter is commonly used in frameworks while making two classes which are not totally compatible with one another to communicate using an Adapter. DotNet framework itself uses Adapter implementation in ADO.NET. We would have used the DataSet class on numerous occasions. The fill method of dataset returns the disconnected dataset in tabular format but internally uses a DataReader to populate the table data from the data source. In this case a data reader is adapted to a data table by the data adapter.
If we are building a framework which can interface with multiple provider we might be better off using Adapter design pattern. Another example that comes to my mind is the unit test runner. Any unit test runner that supports multiple unit testing frameworks will be using an adapter to map between the differences in the naming of various test frameworks. Just to give you an example, consider MSTest which uses TestClass, TestMethod, TestInitialize, TestCleanup as some of the attributes. At the same time NUnit uses TestFixture, Test, Setup and TearDown attributes for similar functionality. So my guess is that a unit test runner like Resharper or TestDriven.Net must be using an adapter for all the unit test frameworks they support.
As always I have uploaded the complete working solution to AdapterDesignPatternDemo.zip
Until next time Happy Programming
Further reading
Here are some books I recommend related to the topics discussed in this blog.
Isn't it similar to Factory Pattern ? What differentiates a Factory Pattern with Adapter Pattern ?
ReplyDeleteFactory is Creational pattern. It is used when we want to centralize the object creation logic and abstract the instanciation logic away from the code which uses the instances of objects.
DeleteAdapter is a Structural patter. It is used to communicate between two interfaces which would not be able to communicate because of their incompatibilities. Whe using factory we have access to the source code and have full control to refactor as per the changing requirements.
Same is not the case with Adapter. In most cases we do not have access to the adaptee class that we are adapting using an Adapter.
The intent is different in implementation of both the Factory & Adapter design patterns.
Thanks ! Implementation looks to be similar however the intent may be different. B'coz the intent of the Factory pattern also to delegate the object creation part to a factory handler class method which creates the respective objects (implements the same base interface or class) based upon the client requirements. Correct ?
DeleteFactory encapsulates the object creation. There is no delegation from factory to another class.
DeleteIn adapter the adapter delegates the call to the actual instance of the adaptee class.
Hope this clariefies the point to you as to when we should be using Factory & when to use adapter pattern.
Thanks Nilesh !
DeleteNice work Nilesh :) Keep it up.
ReplyDeleteBy Khilit (www.bigator.com)
Thanks Khilit
Delete