The Adapter pattern is one of those patterns that requires little imagination to figure out what they do.
First off, let’s see the definition courtesy of GoF:
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 see some code:
class Client def initialize(target) @target = adapter end def do_work # do hard work … @target.complex_operation # ... end end class Target def complex_operation # la la la ... end end
Here’s the story:
Client would be expecting that the
target be able to
do_work without a hitch:
client = Client.new(Target.new) client.do_work
One fine day, your boss comes over, and shows you this class, and tells you that
SomeOtherTarget must work with
class SomeOtherTarget def trivial_operation # oh no! different method name… end end
Obviously, this won’t work, because
SomeOtherTarget does not have the
complex_operation method that the
client = Client.new(SomeOtherTarget.new) client.do_work # DOES NOT WORK
Plugging in the Adapter
We need some way to bridge this difference in interfaces. How do we somehow connect
Client’s expectation of a
complex_operation method with
Adapter class to the rescue:
class Adapter def initialize(adaptee) @adaptee = adaptee end def complex_operation @adaptee.trivial_operation end end
And with this bit of indirection,
Client can happily use
client = Client.new(Adapter.new(SomeOtherTarget.new)) client.do_work # DOES NOT WORK
Notice how now the
Adapter object takes the place of the
@target instance variable of
Adapter object now becomes the middleman/wrapper/translator. This is composition at work!
2 Flavors of Adapters: Object & Class
Now, if you check out the Wikipedia entry you will see the 2 kinds of Adapters - Class and Object adapters.
So what’s the difference?
I don’t know about you, but when I first saw both UML diagrams, my eyes glazed. The key here to to focus on the differences.
The Object Adapter uses composition. Notice that the
Adapter has an
+adaptee field. The
Adapter class has to use the
Adaptee class, and that’s essentially composition.
The Class Adapter uses multiple inheritance (that’s the hollow triangular arrows pointing upwards). Frankly, I don’t know too much about multiple inheritance, and in general, unless you’re a C++ programmer (I’m sorry), you probably won’t need this.
Conclusion: Stick to the Object Adapter.
In the next post, I will look at the Proxy pattern. Thanks for reading!
Olsen, R. (2008) Design patterns in Ruby. Upper Saddle River, NJ: Addison-Wesley, p.163-174.