The Adapter Pattern — A Replacement To Dependency Injection

Devin Dixon
Helium MVC
Published in
4 min readDec 10, 2018

--

PLEASE NOTE: This is an Adapter-Like pattern that is a hybrid of Dependency Injection and Observers to achieve Inversion of Control.

The ProdigyView Toolkit focuses on 3 design patterns to improve development: Adapters, Intercepting Filters and Observers. In this section, we are going to discuss the Adapter Pattern and how it can potentially replace Dependency Injection, and make your application easy to mutate.

Example code usage of the pattern is available here in the Architecture section:

First — Understanding Dependency Injection

For any readers that are new to dependency injection (DI for short), please start by reading this article. It’s a fairly standard design pattern used in development.

One of the problems with DI is that it requires you to re-write an entire class to implement it. You have to know and think about all the aspects of that class, even if there is only one thing you want to change, which can be overkill at times.

One of the advantages languages like Javascript with prototype have is the ability to change out a single function. What if this was available in PHP?

Introducing The Adapter Pattern

The ProgidyView Toolkit allows you to change out single functions without having to modify the entire class. In this tutorial, we are going to teach you how to build one of those classes when writing your application.

Extending PVPattern

This tutorial is assuming you already have the toolkit installed. The first thing we have to do is extend PVPatterns into the class you are creating. Let’s pretend we are building a Messenger application for sending messages.

<php
use prodigyview\design\StaticAdapter;
class Messenger{ //Inherit Adatper Trait
use StaticAdapter;
//Sends the Message
public function send($message) {
MessageService::execute($message);
}
}
?>

Next, we are going to allow other developers to modify the functions we want by implementing the adapter functionality before the execution of the class.

<?php
use prodigyview\design\StaticAdapter;
class Messenger {//Inherit Adatper Trait
use StaticAdapter;

public function send($message) {
//If has an adapter, will call the adaper
if(self::_hasAdapter(get_class(), __FUNCTION__) )
return self::_callAdapter(get_class(), __FUNCTION__, $message);

//Normal Execution
MessageService::execute($message);
}
}
?>

An explanation of the added code:

if(self::_hasAdapter(get_class(), __FUNCTION__) )

This function checks if the there has been adapter assigned by another developer. We will go into that below.

return self::_callAdapter(get_class(), __FUNCTION__, $message);

This function will call another class and return its results instead of following through with the remainder of the method.In other words, the original code never gets executed and the new code does.

And that’s it! We have an adapter successfully implemented. Pretty easy. Next is how to call the adapter.

Calling The Adapter

With the adapter implemented, other developers will need to call it. They can do it through an anonymous function as a closure, or by redirecting it to another class.

Anonymous Function

To briefly summarize, anonymous functions are PHP functions created on the fly and are assignable to a variable. For example:

<?php
$sendMessage = function($message) {
//A fake Facebook function for sending a message
Facebook::sendMessage($message);
}
//Now call the function
$sendMessage(‘Hello Friend’);
?>

Going back to our MessengerApp, we want to change the functionality of sending a message. Because our App extends PVPatterns, we have the ability to add the closure like so:

<?php
Messenger::addAdapter(‘Messenger ‘, ‘send’, function($message) {
//Now can execute return code
echo $message;
return $message . 'Sent via Closure ';
}, array(‘type’ => ‘closure’));
?>

The addAdapter is a function extended by PVPatterns, and we are calling it via our Messenger class. The addAdapter(‘Messenger ‘, ‘send’ is saying: we only want to override the send method of the Messenger class. And then we pass in our new function. With that, the original send method will not be called, and our new method in the closure will be instead.

Calling Another Classes Method

Now if we want to use another class instead of a closure for sending methods, we can redirect the send function to another classes function. Let’s say there is another app called FacebookMessenger:

<?php
class FacebookMessenger {
public static function send($message) {
echo ‘Sending: ‘ . $message;
}
}
?>

The adapter overriding our initial Messenger send function is as simple as:

<?php
Messenger::addAdapter(‘Messenger’, ‘send, ‘FacebookMessenger’);
?>

And that’s it! The first argument is the class you want to override and the 2nd argument is the method you are targeting. And the final argument the class to redirect the function to for processing.

When To And Not Use The Adapter

The Adapter Design Pattern is both powerful and dangerous. It can make re-writing specific functions easier and faster than what DI can offer, but also comes with the risk of exposing important information.

Therefore, an adapter should not be placed in functions that carry sensitive operations and information in the system.

--

--