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:
Normally the 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 Client
:
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
expects:
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 SomeOtherTarget
’s trivial_operation
?
Here’s the 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 SomeOtherTarget
:
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 Client
. The 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.
Object Adapter
(Credits: Wikipedia)
Class Adapter
(Credits: Wikipedia)
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!
References
Olsen, R. (2008) Design patterns in Ruby. Upper Saddle River, NJ: Addison-Wesley, p.163-174.