Continuation of the previous article: PHP behavioral design Patterns (I), introduces the second type of behavioral design patterns.

Between two classes:

  • Observer Pattern
  • Iterator Pattern
  • Chain of Responsibility Pattern
  • Command Pattern

PHP Design Pattern (14) — Observer Pattern

Observer Pattern: Defines a one-to-many dependency between objects. When an object’s state changes, all dependent objects are notified and automatically updated. Also known as publish-subscribe

(I) Why is the observer mode needed

1. The problem of one object notifying other objects of state changes, with ease of use and low coupling to ensure a high degree of collaboration

2. Perfectly separate the observer from the observed object, so that each class focuses on one function and each object does one thing.

3. The Observer pattern sets clear boundaries between modules, improving application maintainability and reuse.

(2) Observer model UML diagram

observer Pattern

(3) Simple examples

The observer model is also called the publish and subscribe model, so let’s say we’re doing a system now. We let all clients subscribe to our server, so that when our server has updates, we notify the client to update. The server is the observed and the client is the observer.

<? php// Abstracts the observed
abstract class Subject{
    // Define an observer array
    private $observers = array();
    // Add observer method
    public function addObserver(Observer $observer){$this->observers[] = $observer;
        echo "Adding observer succeeded".PHP_EOL;
    }
    // Delete the observer method
    public function delObserver(Observer $observer){
        $key = array_search($observer,$this->observers); // Check whether the observer exists
        if($observer===$this->observers[$key]) { // The values are the same but may not be the same object, so use congruence judgment
            unset($this->observers[$key]);
            echo 'Removed observer succeeded'.PHP_EOL;
        } else{
            echo 'Observer does not exist, need not be deleted'.PHP_EOL; }}// Notify all observers
    public function notifyObservers(){
        foreach($this->observers as$observer){ $observer->update(); }}}// Specify the observed server
class Server extends Subject{
    // The observed business publishes a message and notifies all clients
    public function publish(){
        echo 'It's a beautiful day and I've released an update.'.PHP_EOL;
        $this->notifyObservers(); }}// Abstract the observer interface
Interface Observer{
    public function update(); } // Specific observer class // wechatclass Wechat implements Observer{
    public function update(){
        echo 'Notification received, wechat update completed'.PHP_EOL; }}/ / web side
class Web implements Observer{
    public function update(){
        echo 'Notification received, system update on web side'.PHP_EOL; }}/ / app
class App implements Observer{
    public function update(){
        echo 'Notification received, APP will update later'.PHP_EOL; }}// instantiate the observed
$server = new Server ;
// Instantiate the observer
$wechat = new Wechat ;
$web = new Web ;
$app = new App;
// Add the observed
$server->addObserver($wechat);
$server->addObserver($web);
$server->addObserver($app);
// The observed releases information
$server->publish();

// Delete the observer
$server->delObserver($wechat);
// Release the information again
$server->publish();

// Try to delete an object that has not been added as an observer
$server->delObserver(new Web);
// Release the information again
$server->publish();Copy the code

One of the key words of observer mode is trigger, the action of the observed triggers the corresponding response of the observer. Another common area for the observer pattern is in plug-in systems.

Another way to implement an observer in PHP is by implementing the SplSubject interface and SplObserver. This implementation involves SPL (Standard PHP Library) content, which I’ll cover in SPL articles. You are welcome to read the corrections


Iterator Pattern Iterator Pattern

Iterator Pattern: The Iterator Pattern helps groups construct specific objects that provide a single standard interface for looping or iterating over any type of countable data.

(I) Why is the iterator pattern needed

1. We want to iterate over objects, or over a container, in the same way we iterate over arrays.

2. Iterator mode can hide the operations needed to traverse an element

(2) Iterator pattern UML diagram

Iterator Pattern

The above is a UML diagram of iterators from PHP Design Patterns for reference only. Our use of the Iterator pattern in PHP is usually simply an implementation of the Iterator interface.

The following figure shows how to implement the Interator interface

Iterator Interface

(3) Simple examples

Now let’s think of a class as a container that implements the Iterator interface and allows it to be iterated over.

<? phpclass ArrayContainer implements Iterator
{
    protected $data = array();
    protected $index ;

    public function __construct($data)
    {$this->data = $data;
    }
    // Returns the current pointer to the data
    public function current()
    {   
        return $this->data[$this->index];
    }
    / / pointer + 1
    public function next()
    {$this->index ++;
    }
    // Verify that the pointer is out of bounds
    public function valid()
    {
        return $this->index < count($this->data);
    }
    // Reset the pointer
    public function rewind()
    {$this->index = 0;
    }
    // Returns the current pointer
    public function key()
    {   
        return $this->index; }}// Initialize the array container
$arr = array(0= >'in the tang dynasty'.1= >'in the song dynasty'.2= >'the yuan dynasty');
$container = new ArrayContainer($arr);

// Iterate over the container
foreach($container as $a => $dynasty){
    echo 'If I had a time machine, I'd go.'.$dynasty.PHP_EOL;
}Copy the code

An iterator is also similar to a database cursor that can scroll up and down the container, traversing the elements it needs to see.

By implementing the Iterator interface, we can iterate over the data in an object as if it were an array. You might say, well, why don’t I just iterate over an array, why don’t you just throw the array to the container object and iterate over the container object? Well, with the container object, we can hide our foreach operations. For example, if I want to iterate, what if ONE element is output and one element is not output? Using the iterator pattern, you simply change the index++ statement in the next method of the container object to index+=2. You can try that.

Why do current methods have to be implemented to implement an Iterator interface? So when we get a foreach object, PHP automatically calls the valid and next methods for us. The order of the calls, and the implementation of the Iterator interface, is the domain of the SPL (Standard PHP Library). I’ll cover more about the iterator interface in the SPL article. Welcome to point out and exchange.


PHP Design Pattern (16) — Chain of Responsibility Pattern

Chain of Responsibility Pattern: A Chain of recipient objects is created for a request and the request is passed along the Chain until an object processes it. This pattern can decouple the sender and receiver of the request by giving the type of request.

(I) Why is the responsibility chain model needed

1. Decouples the sender of the request from the handler of the request. The handler on the responsibility chain is responsible for processing the request, and the customer only needs to send the request to the responsibility chain, without caring about the processing details of the request and the delivery of the request.

2. The client making the request does not know which object on the chain ultimately processes the request, which allows the system to dynamically reorganize and assign responsibilities without affecting the client

(2) UML diagram of responsibility chain model

Chain of Responsibility Pattern

(3) Simple examples

If we now make an employee system, if the company has regulations that employees have requests for instructions, different people should give instructions according to the level of requests. For example, leave by the group leader instructions, leave by the director instructions, resignation by the general manager instructions. Ok, so how do we do that if we use code? Staff, group leader, supervisor, general manager. So the request of the employee client goes directly to the general manager? Obviously not good. What would it look like if we followed the logic of the real world? (I agree with the statement that any code logic has a real-world equivalent, and if it doesn’t, there’s something wrong with your logic.)

<? php// Abstract handler
abstract class Handler{
    private $next_handler ;// Store the next processing object
    private $lever = 0;             // The processing level defaults to 0
    abstract protected function response(); // The handler responds // sets the processing levelpublic function setHandlerLevel($lever){$this->lever = $lever ;
    }
    // Set the next handler
    public function setNext(Handler $handler){$this->next_handler = $handler;
        $this->next_handler->setHandlerLevel($this->lever+1);
    }
    // If the responsibility belongs to the object, it will be forwarded to the next level. Overwriting is not allowed with final
    final public function handlerMessage(Request $request){
        if($this->lever == $request->getLever()){
            $this->response();
        }else{
            if($this->next_handler ! =null){
                $this->next_handler->handlerMessage($request);
            }else{
                echo 'Go to bed. No one will care.'.PHP_EOL; }}}}// Specific handler
/ / headman team leader
class HeadMan extends Handler{
    protected function response(){
        echo 'Group leader replies: Agree to your request'.PHP_EOL; }}/ / executive director
class Director extends Handler{
    protected function response(){
        echo 'Supervisor replies: Got it, stand down'.PHP_EOL; }}/ manager/manager
class Manager extends Handler{
    protected function response(){
        echo 'The manager replies: Let me think about it before discussing it.'.PHP_EOL; }}/ / request
class Request{
    protected $level = array('off'= >0.'off'= >1.'quit'= >2);// The test is convenient, and the mapping between request levels is set by default
    protected $request;
    public function __construct($request){$this->request = $request;
    }
    public function getLever(){
        // Gets the level of the request, or -1 if there is no level for the request
        return array_key_exists($this->request,$this->level)? $this->level[$this->request]:- 1; }}// Instantiate the handler
$headman = new HeadMan;
$director = new Director;
$manager = new Manager;
// Responsibility chain assembly
$headman->setNext($director);
$director->setNext($manager);
// Pass the request
$headman->handlerMessage(new Request('off'));
$headman->handlerMessage(new Request('off'));
$headman->handlerMessage(new Request('quit'));
$headman->handlerMessage(new Request('pay'));Copy the code

The ConcreteHandler corresponds to the ConcreteHandler in the UML diagram, and the request class corresponds to the client of the UML diagram. By using the responsibility chain, the corresponding processor can have a corresponding single response method. The request only needs to be sent to the lowest level of the handler, judged by the $lever attribute, and then passed layer by layer to the handlers of the same level as the request for the corresponding response. The request does not need to be known; it goes to the appropriate handler. Of course, performance issues can arise when the chain of responsibility is too long. We should avoid using long chains of responsibility for this.


PHP Design Pattern (17) — Command Pattern

Command Pattern: Encapsulating a request as an object, which allows us to parameterize customers with different requests; Queue or log requests, and support undoable operations. Command Pattern is an object behavior Pattern, alias Action Pattern or Transaction Pattern.

(a) Why is the command mode needed

1. Using the command pattern, request sender and request receiver can eliminate the coupling between each other, making the invocation relationship between objects more flexible.

2. Using command mode, it is relatively easy to design a command queue and macro commands (composite commands), and new commands can be easily added to the system

(2) Command mode UML diagram

Command Pattern

(3) Simple examples

A classic example of command mode is television and remote control. If you follow a UML diagram in command mode, there is a correspondence like this: the TV is the receiver of the request, and the remote is the sender of the request. There are some buttons on the remote control, and different buttons correspond to different operations on the TV. These buttons are the corresponding concrete command classes. The abstract command role is played by a command interface, which is implemented by three concrete command classes representing three operations: turn on the TV, turn off the TV, and switch channels.

<? php// Abstract the command role
abstract class Command{
  protected $receiver;
  function __construct(TV $receiver)
  {$this->receiver = $receiver;
  }
  abstract public function execute(); } // Specify the command role boot commandclass CommandOn extends Command
{
  public function execute()
  {$this->receiver->action(); }}// Specific command role Shutdown command
class CommandOff extends Command
{
  public function execute()
  {$this->receiver->action(); }}// Command sender -- remote control
class Invoker
{
  protected $command;
  public function setCommand(Command $command)
  {$this->command = $command;
  }

  public function send()
  {$this->command->execute(); }}// Command Receiver = TV
class TV
{
  public function action()
  {
      echo "Command received, executed successfully.".PHP_EOL; }}// Instantiate the command receiver ------- to buy a TV
$receiver = new TV();
// instantiate the command sender ------- with a remote control
$invoker  = new Invoker();
// Instantiate the specific command role ------- set the remote control keys to match the TV
$commandOn = new CommandOn($receiver);
$commandOff = new CommandOff($receiver);
// Setting command ---------- Press the power button
$invoker->setCommand($commandOn);
// Send the command
$invoker->send();
// Set command ----------- press the shutdown button
$invoker->setCommand($commandOff);
// Send the command
$invoker->send();Copy the code

In practice, command mode receiver is usually an abstract class, that is, it has specific receiver for different commands. The essence of command mode is to encapsulate commands and separate the responsibility of issuing commands from that of executing commands.


PHP Behavioral Design Patterns (part 1)

Thanks for reading. This article is inevitably biased because I am a beginner in design patterns and my abilities are limited


Summary of my recent study:

  • PHP Design Pattern
  • SPL

Welcome to follow my wechat public account Huofengding