Now we have covered all of the creational patterns you should know about (imo). I am steaming ahead on to the structural patterns. The first of which is the adapter pattern 😀
In programming, it’s not rare to build a system, to find out a few months down the line, there are a bunch of new requirements. Originally catering for a particular client or data set and then later having to cater for more and more, this is where the adapter pattern comes into play.
What is the Adapter pattern
The adapter pattern is also commonly called the wrapper pattern, because that’s exactly what it’s doing. You build a class and then you have to write a wrapper/adapter that encapsulate the existing class and slightly manipulates the way it work.
A real world example of this is a main power adapter, your 3 pin plug may work in the uk, but when you go to america, you need an adapter to convert the 3 pin plug into a 2 pin plug.
What is important when building an adapter is that you do not change the behaviour of the original object (the 3 pin plug), all you do is create an adapter to allow the 3 pin plug to work in different environments.
Inheritance Vs Composition
There are two versions of the adapter pattern. The inheritance version also known as the class version and the composition version also known as the object version. As you hopefully know, in programming composition is always favoured over inheritance, due to its looser bindings. For this reason I’ll only be demonstrating the composition version it is entirety, but here is a low down on the inheritance version.
Inheritance
When using the inheritance version, you rely on your adapter class having multiple inheritance. First it should inherit the class it is adapting (think of this as the 3 pin plug) and secondly it should inherit an adapter target class with a collection of adapter methods (think of this as the 2 pin plug). PHP however does not support multiple inheritance out the box, apart from traits which aren’t built for this type of scenario. PHP also supports being able to inherit from one class and implement from another.
The correct way to use this pattern would be to inherit from the class being adapted (3 pin plug) and then implement an interface which would define all of the adapter methods (2 pin plug). Using inheritance over composition has the benefit of not having to define wrappers for methods which do not require any changes. However there is no harm in creating these wrappers in fact I prefer this clarity and it is the recommended choice….. so I won’t be discussing inheritance any further.
If you don’t understand the inheritance concept. Don’t worry, I’ve not explained it great, because you’ll never really have a need for it in PHP. You’re better of grasping composition and than re-reading over the inheritance version if you’re still interested.
Composition
Composition is by far the better known and more commonly used version of the adapter pattern. It relies on your adapter (2 pin plug) being a wrapper for your already existing adaptee class (3 pin plug). All you’re effectively doing is creating an adapter class, passing the adapter an instance of the adaptee and then redefining each of the adaptees methods so they can be called from within the adapter. This allows you to rename methods or even merge multiple methods into one. Thus complying to the new interface requirements.
When to use
As I described above, adapters are used in the real world all the time. Rather than adapting an already existing module and potentially breaking everything. It makes much more sense to make an independent adapter to modify the existing functionality whilst keeping the adaptee fully functional.
Going back to the 2 pin plug adapter idea, you could rewire the 3 pin plug into the 2 pin plug but you’re more liable to break both plugs, where if you create an adapter for the 3 pin plug. The 3 pin plug stays unmodified and you can keep tampering with the 2 pin adapter until it works. Put more simply, you should use the adapter pattern when you need incompatible interfaces to work together. Without breaking existing functionality.
Rules
- Do not modify existing components. If you do you risk breaking old functionality and make using an adapter pointless all together.
Drawbacks
There are no real drawbacks to using the adapter pattern. However there is a fair point, that instead of creating an adapter pattern, code could be refactored instead. If you do not rely on any 3rd parties and you’re programming to an interface, like you should be. You would be able to create a new class with the same interface. Doing so will keep your code much cleaner and maintainable. If however you rely on using 3rd party code it can become extremely handy to create adapters to make incompatible systems work in harmony.
Example
Note: I have dropped adding tonnes of doc-block. As much as I do like them, I’m starting to thing they’re a little OTT for a blog.
/** * interface for creating render classes */ interface RenderTemplateInterface { public function renderHeader(); public function renderBody(); public function renderFooter(); } /** * Used for rendering HTML templates */ class RenderHTMLTemplate implements RenderTemplateInterface { public function renderHeader() { return "<html><body>"; } public function renderBody() { return "Hello World"; } public function renderFooter() { return "</body></html>"; } } /** * Separate interface just for rendering PDF's * Having a separate interface from RenderTemplateInterface could be a requirement from a third party */ interface PDFTemplateInterface { public function renderTop(); public function renderMiddle(); public function renderBottom(); } /** * Used for rendering PDF templates */ class RenderPDFTemplate implements PDFTemplateInterface { public function renderTop() { return "This is the top of the PDF"; } public function renderMiddle() { return "Hello World"; } public function renderBottom() { return "This is the bottom of the PDF"; } } /** * The adapter - this will encapsulate an instance of the RenderPDFTemplate class * to work polymorphically with the RenderTemplateInterface interface */ class PDFTemplateAdapter implements RenderTemplateInterface { private $pdfTemplate; public function __construct(PDFTemplateInterface $pdfTemplate) { $this->pdfTemplate = $pdfTemplate; } public function renderHeader() { return $this->pdfTemplate->renderTop(); } public function renderBody() { return $this->pdfTemplate->renderMiddle(); } public function renderFooter() { return $this->pdfTemplate->renderBottom(); } } $pdfTemplate = new RenderPDFTemplate(); // $pdfTemplateAdapter will implement RenderTemplateInterface, just like RenderHTMLTemplate does $pdfTemplateAdapter = new PDFTemplateAdapter($pdfTemplate); // This is the top of the PDF echo $pdfTemplateAdapter->renderHeader();16 Love This
This article and many other on your page are very interesting.
You should show your content to wider audience. There is a big chance to go viral.
You need initial boost and visitors will flood your
page in no time. Just search in google for:
Juuri13 viral effect