Decorator pattern of PHP design pattern

Keywords: Mobile shell network Laravel

The factory model is over. Let's study some other models. I wonder if you guys have tried women's clothes? It's said that there are many programmers in women's wear. In fact, today's decorator pattern is very similar to that of make-up. I believe that if there is a program in MM, I will be able to explain this design pattern to you immediately.

Gof class diagram and explanation

To decorate these two words, we will temporarily turn him into a make-up. First of all, you have to have a face, then make up, and then put on makeup. You can come to work with light makeup in the morning, or you can go out with heavy makeup when you leave work. Of course, the time when the farmers got off work was just in time for the second half of the night. In other words, no matter how you make up, your face or your face may turn into another person you don't know, but it's really your face. This is the decorator. It can decorate the object (face) to make the face more beautiful (increase responsibilities).

GoF definition: dynamically add some extra responsibilities to an object. In terms of adding functions, Decorator pattern is more flexible than subclass generation

GoF class diagram

code implementation

interface Component{
    public function operation();
}

class ConcreteComponent implements Component{
    public function operation(){
        echo "I'm face!" . PHP_EOL;
    }
}

A very simple interface and an implementation, here we regard the concrete implementation class as a face!

abstract class Decorator implements Component{
    protected $component;
    public function __construct(Component $component){
        $this->component = $component;
    }
}

The abstract decorator class implements the Component interface, but does not implement the operation() method. Let the subclass implement it. Here we mainly save a reference of composnet, which will be decorated later. Corresponding to the above specific categories, we are ready to make up for the face!

class ConcreteDecoratorA extends Decorator{
    public $addedState = 1; // Properties that have no practical significance, but are different from concretedecorator B

    public function operation(){
        echo $this->component->operation() . "Push " . $this->addedState . " cream!" . PHP_EOL;
    }
}
class ConcreteDecoratorB extends Decorator{
    public function operation(){
        $this->component->operation();
        $this->addedBehavior();
    }

    // It's just different from concrete decorator a
    public function addedBehavior(){
        echo "Push 2 cream!" . PHP_EOL;
    }
}

Two specific decorators. I've applied two creams here. After all, I'm a pure man. I really don't know about makeup. It seems that the first step should be foundation. But this time, what we two decorators achieve is to apply two layers of cream to the face.

  • As you can see from the code, we always wrap the concrete concrete component object
  • In fact, we've wrapped his operation() method twice, adding a little something on the basis of the previous one
  • Don't get tangled in the added properties and methods of A and B decorators. They are just used to distinguish the two decorators in the GoF class diagram. Each decorator can do many other things. The Component object doesn't have to only have the operation() method. We can selectively decorate all or part of the methods in the object
  • It seems that we all inherit the Component. It's OK to rewrite the subclass all the way. What's the trouble? Dear, understand the concept of composition. Our Decorator parent class contains a reference to a real object. It decouples itself. We only wrap the real object. You can't instantiate the Decorator directly
  • Still don't understand? What are the benefits? How dare you change the old system? If you want to extend the new function to the code written by your predecessor, you may want to try the decorator. It may have a wonderful effect!

Mobile phones can't do anything but rice, O and work. It's impossible to play. OK, let's concentrate on making mobile phone cases! Well, I prepared a transparent shell first. It seems a little ugly. I can't help it. Who is brother poor. Add a variety of solid colors (decorator A1) to a certain meter, and then print a variety of colors of plants (decorator B1) on the back; a certain O's mobile phone recently likes to look for traffic to make an obvious endorsement, so I use a variety of colors (decorator A2) and a star's cartoon head (decorator B2) for his mobile phone shell; finally, it seems that the mobile phone has started to lead the industry trend, folding screen It's not going to smash my cell phone shell business!! OK, I won't do it for you. I'd better go with my rice and O!!

Full code: Decorator mode

example

Continue to send SMS, before we used the factory mode to solve the problem of multiple SMS operators. This time we are going to solve the problem of SMS content template. For promotional SMS, according to the latest advertising law, we can't use words like "No.1 in China" and "No.1 in the world". Of course, we can't use some uncivilized words.

Now, we have a long time ago SMS template class. The content is fixed. The old system still uses this template. The old system is facing internal employees, and the requirements for language content are not high. The new system needs to be sent to the whole network, that is, internal and external users have to send. At this time, we can use the decorator mode to package the SMS template of the old system. In fact, to put it simply, we use decorators to do the function of text replacement. What are the benefits? Of course, you can modify and extend the content of the old template without changing the methods in the original template class.

Class diagram of SMS sending

Full source: SMS sending decorator method

<?php
// SMS template interface
interface MessageTemplate
{
    public function message();
}

// Suppose there are many templates to implement the above short message template interface
// Here is a template implementation of coupon sending
class CouponMessageTemplate implements MessageTemplate
{
    public function message()
    {
        return 'Coupon information: we are the first cattle in the country X Product Oh, send you ten coupons!';
    }
}

// Let's get ready to decorate the old SMS template on it
abstract class DecoratorMessageTemplate implements MessageTemplate
{
    public $template;
    public function __construct($template)
    {
        $this->template = $template;
    }
}

// Filtering words not allowed in the new advertising law
class AdFilterDecoratorMessage extends DecoratorMessageTemplate
{
    public function message()
    {
        return str_replace('No.1 in China', 'Second in the country', $this->template->message());
    }
}

// Use the new words library automatically generated by colleagues in our big data Department to filter sensitive words. This filtering is not mandatory. You can choose to use
class SensitiveFilterDecoratorMessage extends DecoratorMessageTemplate
{
    public $bigDataFilterWords = ['cattle X'];
    public $bigDataReplaceWords = ['Easy to use'];
    public function message()
    {
        return str_replace($this->bigDataFilterWords, $this->bigDataReplaceWords, $this->template->message());
    }
}

// Client, send interface, need to use template to send SMS
class Message
{
    public $msgType = 'old';
    public function send(MessageTemplate $mt)
    {
        // Send it out
        if ($this->msgType == 'old') {
            echo 'Send to intranet users' . $mt->message() . PHP_EOL;
        } else if ($this->msgType == 'new') {
            echo 'Send to all network users' . $mt->message() . PHP_EOL;
        }

    }
}

$template = new CouponMessageTemplate();
$message = new Message();

// The old system does not need filtering, only internal users can see it
$message->send($template);

// The new system, for the whole network, needs to filter the content
$message->msgType = 'new';
$template = new AdFilterDecoratorMessage($template);
$template = new SensitiveFilterDecoratorMessage($template);

// It 's filtered. Send it
$message->send($template);

explain

  • The biggest advantages of decorators: first, expand the content of the original code without changing the original code, open and closed principle; second, each decorator completes its own function, single responsibility; third, realize the sense of inheritance with combination;
  • Most suitable for: extending the old system
  • Be careful: too many decorators will make you dizzy
  • It's not necessarily to decorate the same method. In fact, the decorator should be more used to decorate and extend the object. Here we are all aiming at the output of a method to decorate, but only limited to this article, the application of decorator is actually more extensive
  • The feature of decorators is that they all inherit from a main interface or class. The advantage is that the returned object is the same abstract data and has the same behavior attribute. Otherwise, it is not the object before decoration, but a new object
  • It doesn't matter if it's a bit hard to understand. Our example is actually very reluctant. In Head First design mode, this design mode mentioned that Java's I/O series interface uses this design mode: FileInputStream, LineNumberInputStream, BufferInputStream, etc
  • The middleware pipeline in Laravel framework is actually a comprehensive application of multiple modes, including the decorator mode: Laravel HTTP: source code analysis of Pipeline middleware Decorator Pattern
  • In addition, in Laravel, log processing also decorates the Monolog. Students who are interested in it can learn about it

Next issue

It's daga again. Do you understand the power adapter? Have you ever seen a transformer? You may or may not have used it, but you must have heard of this very, very famous adapter mode.

===============

Official account: hard core project manager

Add wechat / QQ friends: [darkmaterzycoder / 149844827] free PHP and project management learning materials

Posted by ChrisBoden on Tue, 16 Jun 2020 20:21:21 -0700