Hi all!

Today I am starting a post series about Design Patterns. I have wrote about them a lot but only suggesting you to learn about to be a better developer. I am studying them, so nothing better to write about and improve my knowledges too.

I only ask you to read everything to understand the concepts behind the patterns. You have to understand them to know where you can use one or another.

The Adapter Pattern

The Adapter Pattern is exactly what it is, an adapter. It works to allow you to adapt your code to a new requirement that did not exist before "now".

Let's suppose you are working on a project where you have a website and have to allow users to write on the company's Twitter profile. You can have the follow situation:

  • Post.php: Your post class. This is the Post object, where you have text and a URL, for example.
  • Twitter.php: The Twitter class. It can be a class created by you or for example a class you got in Packagist website.

Good. So, you could write a code like that:

<?php 

// creating a post and posting to Twitter
$post = new Post();
$post->description = 'My first post to Twitter. Just for fun!';
$post->url = 'http://juniorgrossi.com';
$post->send();

// inside Post class
class Post
{
    // ... code and more code

    public function send()
    {
        $text = $this->description . ' ' . $this->url;
        // some Twitter class
        $twitter = new Twitter();
        // authenticate and more ...
        $twitter->tweet($text);
    }
}

Ok! That works! Solve your problem perfectly, so it is a very good approach.

But now someone tells you that you have to change the code and choose to post to Twitter or Instagram. Ok! It's easy!

<?php 

// changing the Post class
class Post
{
    public function send($service = 'twitter')
    {
        if ($service == 'twitter') {
            $twitter = new Twitter();
            // ...
            $twitter->tweet();
        } elseif ($service == 'instagram') {
            $instagram = new Instagram();
            // ...
            $instagram->postToInstagram();
        }
    }
}

Ok! It works! But you can do better than that. Now it is the opportunity to you to use a pattern, the Adapter Pattern. You can adapt you code to a generally solution, just changing the service you want. If you have now to include Facebook too, you will do that easy, and not change the send() method again and include one more if condition. Do that is a very bad idea!

Creating the Service Interface

Here you have 2 different services: Twitter and Instagram. The first one uses a method to "post" called tweet() and the second another method called postToInstagram(). First you have to create a pattern, with one method that will be responsable to post to the service, don't matter what is. It's the chance you have to create a Interface. Take a look!

interface ServiceInterface
{
    public function authenticate(array $options);

    public function post($text, $url);
}

Just that. Here is the secret of your developer's life! Use Interfaces for everything! This interface has, for example, two methods: one to authenticate in the service and another to post the text to the service. Now you will create two more classes (pay attention them implements the interface you've created):

class TwitterService implements ServiceInterface
{
    protected $service;

    public function __construct()
    {
        $this->service = new Twitter();
    }

    public function authenticate(array $options)
    {
        $apiKey = $options['api_key'];
        // ...
        $this->service->authenticateUsingSomeMethod($apiKey);
        // ...
    }

    public function post($text, $url)
    {
        // ...
        $this->service->tweet($text . ' ' . $url);
        // ...
    }
}

class InstagramService implements ServiceInterface
{
    protected $service;

    public function __construct()
    {
        $this->service = new Instagram();
        $this->service->someAnotherMethodYouHaveToCall();
    }

    public function authenticate(array $options)
    {
        // ...
        $this->service->authenticateWithInstagramClass();
        // ...
    }

    public function post($text, $url)
    {
        // ... 
        $this->service->postToInstagram($text);
        // ...
    }
}

And let's change the Post.php class for the last time :D

class Post
{
    protected $service;

    public function setServiceAdapter(ServiceInterface $service)
    {
        $this->service = $service;
    }

    public function send()
    {
        $this->service->post($this->description, $this->url);
    }
}

Now, to use the Post class you have to instantiate, set description and url properties, provide the ServiceInterface object and call the send() method:

// creating a post and posting to Twitter, Instagram or Facebook
$post = new Post();

// if want to use Twitter
$post->setServiceAdapter(new TwitterService()); // OR

// if want to use Instagram
$post->setServiceAdapter(new InstagramService()); // OR maybe

// if want to use Facebook or another social network adapter
$post->setServiceAdapter(new FacebookService());

$post->description = 'My first post to Twitter. Just for fun!';
$post->url = 'http://juniorgrossi.com';
$post->send();

This way you can create new adapters without change your Post code. Your Post class use a Interface and only classes that implements that interface will have those methods, the methods that Post class uses to send a post.

That's all! I wish explain a little about the Adapter Pattern. If you can improve this post with another example or correcting me with something please tell me. You are welcome to contribute and share!

Thanks for reading!