Skip to content

Latest commit

 

History

History
216 lines (169 loc) · 5.37 KB

10.md

File metadata and controls

216 lines (169 loc) · 5.37 KB

Lesson 10: Design Patterns

Program to an interface, not an implementation.

We learned an interface is a set of methods that an object responds to, and an implentation is the code and logic for the object. Generally, when you want to write code, you want to reference interfaces instead of implementations.

This decouples design from the specific implementation of concrete classes, and allows you to swap out one implementation for another easily, as well as create new implementations.

In PHP we can accomplish this by specifying interface data types in type hinting. It is important to note that by 'interface data types', we mean interfaces or abstract classes.

Also, as previously noted, we can instantiate an object of a given concrete implementation, and as long as it implements an interface or extends an abstract class, it will comply with the type hinting.

Favor object composition over class inheritance.

If at all possible, try to create client classes that are composed of various objects.

Consider the following classes:

  1. Inheritance
<?php

class Pet {
  function speak() {
    echo 'speaking';
  }
}

class Dog extends Pet {
  function bite() {
    echo '\/\/\/';
  }
}

class Client {
  function __construct() {
    $dog = new Dog();
  }
}

This contrived example shows a client class that uses an object.

Strategy

Encapsulating specific families of algorithms allows the client class responsible for instantiating a particular algorithm to have no knowledge of the actual implementation.

<?php

interface OutputInterface
{
    public function load();
}

class SerializedArrayOutput implements OutputInterface
{
    public function load()
    {
        return serialize($arrayOfData);
    }
}

class JsonStringOutput implements OutputInterface
{
    public function load()
    {
        return json_encode($arrayOfData);
    }
}

class ArrayOutput implements OutputInterface
{
    public function load()
    {
        return $arrayOfData;
    }
}

Singleton

A singleton is a class that is intended to be instantiated once and reused in multiple scopes in an application.

<?php

class Singleton
{
    /**
     * Returns the *Singleton* instance of this class.
     *
     * @staticvar Singleton $instance The *Singleton* instances of this class.
     *
     * @return Singleton The *Singleton* instance.
     */
    public static function getInstance()
    {
        static $instance = null;
        if (null === $instance) {
            $instance = new static();
        }

        return $instance;
    }

    /**
     * Protected constructor to prevent creating a new instance of the
     * *Singleton* via the `new` operator from outside of this class.
     */
    protected function __construct()
    {
    }

    /**
     * Private clone method to prevent cloning of the instance of the
     * *Singleton* instance.
     *
     * @return void
     */
    private function __clone()
    {
    }

    /**
     * Private unserialize method to prevent unserializing of the *Singleton*
     * instance.
     *
     * @return void
     */
    private function __wakeup()
    {
    }
}

class SingletonChild extends Singleton
{
}

$obj = Singleton::getInstance();
var_dump($obj === Singleton::getInstance());             // bool(true)

$anotherObj = SingletonChild::getInstance();
var_dump($anotherObj === Singleton::getInstance());      // bool(false)

var_dump($anotherObj === SingletonChild::getInstance()); // bool(true)

Factory

A factory class simply creates the object you want to use. The purpose of the factory pattern is to separate the object being created from implementation and instance management.

<?php

class Automobile
{
    private $vehicleMake;
    private $vehicleModel;

    public function __construct($make, $model)
    {
        $this->vehicleMake = $make;
        $this->vehicleModel = $model;
    }

    public function getMakeAndModel()
    {
        return $this->vehicleMake . ' ' . $this->vehicleModel;
    }
}

class AutomobileFactory
{
    public static function create($make, $model)
    {
        return new Automobile($make, $model);
    }
}

// have the factory create the Automobile object
$veyron = AutomobileFactory::create('Bugatti', 'Veyron');

print_r($veyron->getMakeAndModel()); // outputs "Bugatti Veyron"

Dependency Injection

Drupal 8 introduces the concept of services to decouple reusable functionality and makes these services pluggable and replaceable by registering them with a service container. As a developer, it is best practice to access any of the services provided by Drupal via the service container to ensure the decoupled nature of these systems is respected.

An injection is the passing of a dependency (a service) to a dependent object (a client). The service is made part of the client's state, either by passing them as arguments to a constructor or injected via setter methods. Passing the service to the client, rather than allowing a client to build or find the service, is the fundamental requirement of the pattern.

References