Introduction 

There is no real reason to pick these three patterns for the first blog on series of pattern related blogs. It's just that we had to make a start, somewhere !  But these three patterns are very interesting and to some extent very similar. Consider a diagram below ­                              

Client → Adapter → Original Class                             

Client → Façade → Original Class                             

Client → Proxy → Original Class

What does it mean ? There is not much to separate between these three at least when you look at them as something in between client and original class. Now they just look like mere names but nothing more. But as we will go into the details you will see that how different they are from each other but from this runtime view, it feels like they are pretty much similar. Let's get into a bit of details.

 

Adapter Pattern

Remembering the Intent

GoF Definition (P. 139/ First Edition) ­ “Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.”

 

Many folks feel that the best way to remember a pattern is to remember it's intent. You have the Adapter pattern's intent above taken directly from GoF. How hard it could be to remember it ? At the end of the day if you have to remember all the GoF patterns intent then things might start spinning a bit, that is what we want to avoid. There is one more way of remembering the pattern. Take the most useful and most commonly used real life example used by the community (in books, blogs, etc) and see if understanding that makes sense. In case of Adapter when I was looking around for a good example I found many but the one which stood out from the crowd is below but a word of caution. There might be edge cases in all the examples which we need to probably understand and we will try to cover them also. Now on to the example, here it is


 

"The best example for the adapter pattern is based around AC power adapters. Say you're visiting US from the India, with your laptop, which expects a India power supply. To get your laptop plugged in, you're going to need to get a power adapter that accepts your India plug and allows it to plug in to the US power outlet. The AC adapter knows how to deal with both sides, acting as a middleman ­ this is the adapter pattern"

 

Above is a real world example and if you travel abroad you must have definitely come across a situation like this. This is one good example which can help us to remember this pattern's intent.

 

Once we are more or less okay about the intent of the pattern which in this case is to get a middleman who can satisfy client's needs since the original system does satisfy that need for some reasons. Also in this process the client should not suffer much. Now it's time we can dwell into some more details.  The first detail that I would like to touch base here is about when shall we use this pattern or when do we know is the rite time in the phase of SDLC that this pattern might have a chance to get in to the code system ? One such time is the requirement's phase. If you happen to document your requirements well or discuss it well with the architects or engineers the chances are that they will hopefully raise their hands and say “Mr.Client facing guy or software requirement gathering guy, I have a definite feeling that we can use an Adapter pattern here”. There is an irony here and that is most of the times these guys won't give it a damn but the point is that requirement or analysis phase does look like a good time to get the magnifying glass and see if there is a chance for a patten to get in. While developing an enterprise level application sometimes it might happen that you will interact with an existing system. When you do that your own system under development might need something from the existing system and it is very very seldom that the existing system will have the output the way you wanted it. The existing systems interface would not probably match your interface which is under development. So it's a mismatch but you need that exiting system,'s stuff since it is good stuff but it has a screwed up interface. Now you won't be bold and brave enough to fix the exiting system to suit your need. Imagine travelling to US and fixing the way electricity is generated in the US so that it suits your laptop ! Well, better get an adapter. So the point to remember is that you might need an adapter if you are interacting with the existing system which does not match your systems interface. You have to somehow make that external interface work with your system in as smooth fashion as possible.Let's look at the class diagram of an Adapter pattern as shown in GoF book

 

 

 


 

 

Who's who  ?'

Client – this is the caller and you might be writing this code.

Target – is the code that the client calls and target is the one which is implemented by many classes and you must be the one writing that code. So target is generally the interface that you are writing.

Adapter – is the class that has implemented the interface (Target) in order to adapt the Adaptee ! What it means is that Adapter is also a normal class but it's job is to interact with an external interface without which your client can't live, at least for some of the use cases (remember your laptop in a foreign land, can't live with their electricity so needs an adapter).  Please do remember at this point of time that Target interface will also be implemented by many other classes but those are the ones which are okay and they are your classes, all with the rite kind of interface and hence very compatible with the system that you are developing. In GoF book this is not explained much in detail, this is what they expect us to know.

Adaptee – have you guessed it by now ? It is that external interface that we need but it is just not compatible with our system. So an Adapter must adapt and Adaptee, so that it's output can be used by the current system without the client knowing about it.


 

Java Code and One More Very Simple Example ­Let' finish it off with a simple example. Assume that you have to generate graphs in your system. Line, Pie and Bar graphs are the only one that you need. So the system is designed and we can at the bare minimum do something like this ­

 

 

 

So we have one interface Graph  and we have three classes BarGraph, PieGraph, LineGraph derived from this interface. So far so good this is the system that you always wanted, this is your system. Now tomorrow comes a requirement where you have to develop another type of graph called the RadarGraph and the best part is that this code exists and it is written by someone else. Now some one else regard graph has everything (well almost) you want and it is available, so all you need to do is to use it by building an Adapter which will adapt the Adaptee (External RadarGraph). For the sake of this discussion let us assume that the external RadarGraph is called well, ExternalRadarGraph. Now it is very fair to assume that it has been derived from a different interface (and not Graph because that is your interface). So the external interface and the your interface are not compatible (this is the time to go back and read the GoF definition once again now). So the challenge is to make these two interfaces compatible by using an Adapter. Let's do that, see the diagram below ­- 

 

 

 


 

If you look at the above diagram can you guess which is the Adaptor ? Of course it is RadarGraph ! It could have been named as RadarGraphAdaper to make it more obvious.

5 points to ponder now ­ -

1) A dark colour diamond shape arrow which goes from ExternalRadarGraph to RadarGraph means that RadarGraph contains ExternalRadarGraph. When it comes down to coding this is it simple. It is just the matter of creating an object of ExternalRadarGraph in RadarGraph and calling the method (show()) in this case from RadarGraph's display() method. That's it !

2) The above approach in some ways promotes the following ­          

a) Encapsulation          b) Polymorphism

3) In the above example you will also notice that if the Client wants a RaqdarGraph for which we would need the services of the Adapter then it id going to generate more objects in system, say when we compare it with a situation when Client wants a BarGraph. Client does not know that it is dealing with more objects at this point of time or less objects at some point of time. Adaptee is completely wrapped by the Adapter and hence this pattern is also referred to as a Wrapper.

4) Assume that in the above example Adapter had to do some work in order to get the kind of Graph our system (the one that you have developed/developing) is used to. For example let's assume that ExternalRadarGraph returns a 100kb graph and we have a system where we want only 10kb or less than that when it comes to Graph size. Maybe it's not a very bad idea for the Adaptor to take care of that. It's better than generating the Graph itself ! But what if now we don't have all the colours in RadarGraph (which comes from ExternalRadarGraph)? Again in order to make it consistent with our system we need to fix that too.  The point I am trying to make here is that it is okay to do some tasks by the Adaptor but nor whole bunch of tasks since that is not the intent of an Adaptor.

5) We have used Strategy pattern with this pattern which is a good idea to take care of variation of behaviour as shown above (Line, Bar, Pie graph are variations)

 

cheers !

rohit

 

References - 
1) GoF – Gang of Four  ­ 

 

Views: 155

Tags: Adapter, Design, Encapsulation, GoF, OOP, Pattern, Patterns, Polymorphism

Comments are closed for this blog post

© 2013   Created by Rohit Pant.

Badges  |  Report an Issue  |  Terms of Service