Design Patterns Uncovered: The Adapter Pattern

Continuing our series of articles, taking each design pattern one by one, we move onto the Adapter pattern. This pattern is used a lot in Eclipse, allowing plug-ins to be loosely coupled, yet still be integrated into the Eclipse runtime. 

Adapters in the Real World 

A real world analogy always helps with the understanding of a design pattern. The best example for the adapter pattern is based around AC power adapters. Say you're visiting Europe from the US, with your laptop, which expects a US power supply. To get your laptop plugged in, you're going to need to get a power adapter that accepts your US plug and allows it to plug in to the European power outlet. The AC adapter knows how to deal with both sides, acting as a middleman - this is the adapter pattern.

Design Patterns Refcard
For a great overview of the most popular design patterns, DZone's Design Patterns Refcard is the best place to start. 

The Adapter Pattern

The Adapter is known as a  structural pattern, as it's used to identifying a simple way to realize relationships between entities. The definition of Adapter provided in the original Gang of Four book on Design Patterns states: 

Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.

Let's take a look at the classic diagram definition of  the adapter pattern:

The Target interface defines the domain specific interface that the Client used, so the client collaborates with objects that implement the Target interface. On the other side of things, the Adaptee is the existing interface that needs adapting in order for our client to interact with it. The Adapter adapts the Adaptee to the Target interface - in other words, it translates the request from the client to the adaptee. 

Let's take a look at the interactions in a sequence diagram: 

In this example, as far as the Client is concerned it's just calling the request method of the Target interface, which the Adapter has implemented. In the background however, the Adapter knows that to return the right result, it needs to call a different method,specificAdapteeRequest, on the Adaptee.

Note: the pattern described here is the object adapter. There is a class adapter pattern, but you need multiple inheritance to use it. Seeing as Java doesn't support multiple inheritance, I'm going to leave this out.

Where Would I Use This Pattern?

The main use of this pattern is when a class that you need to use doesn't meet the requirements of an interface. As mentioned before, adapters are common across Eclipse plug-ins. For a particular object to contribute to the Properties view, adapters are used display the objects data. The view itself doesn't need to know anything about the object the it is displaying properties for. 

So How Does It Work In Java?

The following example shows a simple implementation of the pattern. Consider that we have a third party library that provides sorting functionality through it's NumberSorter class. This is our Adaptee.

01. /*
02. * This is our adaptee, a third party implementation of a
03. * number sorter that deals with Lists, not arrays.
04. */
05. public class NumberSorter
06. {
07. public List<Integer> sort(List<Integer> numbers)
08. {
09. //sort and return
10. return new ArrayList<Integer>();
11. }
12.  
13. }

Our Client deals with primitive arrays rather than Lists. For the sake of this example, lets say we can't change the client to use Lists. 

1. int[] numbers = new int[]{3424121};
2.  
3. Sorter sorter = new SortListAdapter();
4. sorter.sort(numbers);

We've provided a Sorter interface that expects the client input. This is our target.

1. //this is our Target interface
2. public interface Sorter
3. {
4. public int[] sort(int[] numbers);
5. }

Finally, the SortListAdapter implements our target interface and deals with our adaptee, NumberSorter

 

01. public class SortListAdapter implements Sorter
02. {
03.  
04. @Override
05. public int[] sort(int[] numbers)
06. {
07. //convert the array to a List
08. List<Integer> numberList = new ArrayList<Integer>();
09.  
10. //call the adapter
11. NumberSorter sorter = new NumberSorter();
12. numberList = sorter.sort(numberList);
13.  
14. //convert the list back to an array and return
15.  
16. return sortedNumbers;
17. }
18.  
19. }

While this example may be overkill, it illustrates how the adapter pattern can work.

Watch Out for the Downsides

Some say that the Adapter pattern is just a fix for a badly designed system, which didn't consider all possibilties. While this is a fair point, it is an important part of a pluggable architecture.  It can also add a level of complexity to your code, making debugging more difficult.

Other Articles in This Series
The Observer Pattern 
The Adapter Pattern
The Facade Pattern
The Factory Method Pattern
The Abstract Factory Pattern
The Singleton Pattern
The Strategy Pattern
The Visitor Pattern

Next Up

 We're going to get around to discussing the Facade pattern later this week. Stay tuned!

Tags: 

Comments

Eyal Golan replied on Tue, 2010/02/09 - 10:18am

Nice article.

The series of DP in Java is a great idea.

I have a question, which  always confused me. In java-swing, there are all the Adapters classes that implement some interfaces. Example: MouseAdapter implements EventListener and MouseListener. I know why they are there and what they are used for, but what about the name? As far as I understand, these are not the case of DP Adpater. Or is it?

 

James Sugrue replied on Tue, 2010/02/09 - 10:31am in response to:

Thanks Eyal

Another description for Adapter would be wrapper. As such, I think that MouseAdapter could be considered to follow the Adapter pattern.

James

Tony Izzo replied on Tue, 2010/02/09 - 11:05am in response to: James Sugrue

Actually, I'm not sure I agree, because the *Adapter classes in Swing don't wrap or adapt anything, they are merely default, empty implementations of their corresponding interfaces.

I'm not sure when Design Patterns first came out, but is it possible that maybe Swing simply predated it, and these classes were therefore named at at time when "Adapter" didn't mean anything so specific as it does today?

Tony

Greg Helton replied on Tue, 2010/02/09 - 5:57pm

They are adapters because AWT is implemented with different native components on different platforms - Mac, Windows and *nix. From wikipedia - "AWT widgets provided a thin level of abstraction over the underlying native user interface". Mac, Windows and *nix provide different APIs to their UI components. The AWT adapters give Java developers a common interface to the different APIs hence, the Adapter pattern.

Sumit Bansal replied on Tue, 2010/02/09 - 9:10pm

Brief yet precise, great article.

ALVARO VILAPLAN... replied on Fri, 2010/02/12 - 8:21am

Nice article. I recommend you to read "Anticorruption layer" in the 'Domain Driven Design Tackling Complexity in the Heart of Software' or in my blog http://azajava.blogspot.com/2010/02/beyond-technologies-domain-driven.html. Regards

Elwyn Malethan replied on Thu, 2010/02/25 - 6:09am

Maybe I'm missing something. Isn't this series just a regurgitation of the Design Patterns (GoF) book?  What added value does it provide over the book? Beyond being free that is.

John Turner replied on Wed, 2010/03/31 - 7:56am

Hi Elwyn,

I would say the added value is in the discussion the article prompts.  As you say the vanilla design patterns are already well documented but reading something and understanding it are two different things.  The real understanding comes from discussing different flavours of the pattern and the trade offs that lead to that particular implementation.

One thing I would add to the article would be to note that the Adapter should maintain the original behaviour.

John

Nmatrix9 Nmatrix replied on Sun, 2010/04/04 - 1:48pm

Hey guys looking at the last example of the snippet of code and it has me thrown off a bit:

The numbers array parameter in line 5 (of last code snippet) is not being used anywhere in the sort method?  How is anything in the array being converted/sorted when it is not being used?  Unless I'm missing the obvious, please clarify. Thanks, 

 

Nmatrix9 Nmatrix replied on Sun, 2010/04/04 - 1:46pm

@Elwyn Malethan

"Maybe I'm missing something. Isn't this series just a regurgitation of the Design Patterns (GoF) book?  What added value does it provide over the book? Beyond being free that is."

 The added value it provides over the book at least for me is "short and sweet".  In about 5 pages I learned (and I mean REALLY learned) more about the adapter pattern than I could in a hundred.  I finally was able to grasp the ESSENCE about what the pattern was about.  Contrast that with many other "patterns" book and they use very abstract language when in essence the principal and practice of the pattern is simple.  Hell we need more articles like these in general. 

Murug Annamalai replied on Sat, 2011/12/31 - 12:02pm

Sweet and concise article. I like the mention of the drawbacks
  • "Adapter pattern is a fix for already created bad design- ie not accommodating for clients". Even with a very good design, class which was once created would become a legacy class as more and more clients start using it.So at one point of time,we might have to use adapters
  • "Adapter add a level of complexity to your code" -That's true.If there are no proper naming conventions and comments, the code is difficult to follow through.We can minimize the complexity by modularizing the legacy class/application and adapter in seperate jars.And also with loose coupling-May be legacy application could expose as a rest service

Vithuran Rahul replied on Thu, 2012/10/11 - 4:34am

 

 

Manoj Kumar replied on Sat, 2013/09/28 - 1:35am

 What is Adaptor

Adaptor is used to make tow parties talk with each otherwise could not talk as their communication channel is not compatible with each other

For Example :

Adaptor for a mobile charger : Mobile can not be directly plugged in to electric socket to charge it . It between it requires an adaptor to to get connected. Adaptor converts 220V from electric socket to 9V what Mobile is made to accept .

An interpreter between two people talking two different languages unknown to each other. Interpreter acts as adaptor here.

Let me take you through java code How we can easily implement and use this pattern in java.

A class A has a method m which takes two parameters String ,String But client who wants to invoke that method does not have a pair of strings but has a Map . So how will they talk . We will insert one more class between then which will act as adaptor . It will take input from client ,will covert the Map parameters in String,String pair combinations and will call the class A method m . Thus client and service class A are not talking with each other directly and Adaptor is making their communication possible.

Here is example with java code . I have written are steps in system.out.println statements in methods

<a href="http://efectivejava.blogspot.in/2013/09/java-adaptor-design-pattern.html?utm_source=BP_recent">Adaptor Design Pattern</a>

http://efectivejava.blogspot.in/2013/09/java-adaptor-design-pattern.html?utm_source=BP_recent

Andrew Carlson replied on Thu, 2014/01/23 - 8:03pm in response to: Nmatrix9 Nmatrix

You are correct. This is terrible code that doesn't even work as pseudo-code.

NumberSorter.sort() essentially takes a List<Integer> and casts it to an ArrayList<Integer>.

That is the first thing the SortListAdapter class does in its overridden sort() method.

That means it was pointless to call the NumberSorter class in the first place.

Additionally, the argument passed to the SortListAdapter.sort() method is never used, meaning the numbers you passed in will never get sorted. 

On top of that, SortListAdapter.sort() returns a variable called sortedNumbers. That was never declared anywhere. That would throw a compile time error. 

Try this:

01. public class SortListAdapter implements Sorter
02. {
03. @Override
04. public int[] sort(int[] numbers)
05. {
06. //convert the array to a list
07. List<Integer> numberList = Arrays.toList(numbers);
08.  
09. //call the adapter
10. NumberSorter sorter = new NumberSorter();
11. List<Integer> sortedNumbers = sorter.sort(numberList);
12.  
13. //convert the list back to an array and return
14. Integer[] numberArray = sortedNumbers.toArray();
15.  
16. //and since the whole point of this pattern explanation was to return primitives
17. int[] sortedPrimitiveInts = org.apache.commons.lang3.ArrayUtils.toPrimitive(numberArray);
18.  
19. return sortedPrimitiveInts;
20.
21. }

Sameera Nelson replied on Fri, 2014/03/14 - 11:27am

I think in the integration aspects Adapter pattern is a time saver. And I don't think such situations occur due to bad designs. 

For an example lets think about a situation where we have to write a client for a specific service (third party). So we started with web service on SOAP, but after some time the communication channel get changed (third party decision) to some other like REST, still with same old parameters.

Here if we had our design with the Adapter patter, it would be a new Adapter with required parameter translation (to/from domain specific), else rewriting client flow from an earlier stage(may be from the scratch ) as it was written bounded to the specific service (Obviously you have to write a  new connector anyway in both cases).

So bad design is not related if this is a integration platform.

Any comments ?

Shay Tavor replied on Wed, 2014/03/26 - 5:16am in response to: Sameera Nelson

I agree with you - I think that the adapter gives a great solution for legacy systems, and it doesn't imply bad design (the other option is sometimes to write the legacy system from scratch, and I guess this is a worse solution).

I have yet another question regarding this article - wouldn't this sorter utility be better implement via Strategy pattern? And in the wider context - can Strategy and Adapter be interchangeable?

Shay


Reference: http://java.dzone.com/articles/design-patterns-uncovered-0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值