图片 1

PHP设计形式之权利链方式的入木柒分分析,人人都能读懂的设计方式

By admin in 编程 on 2019年7月23日

责任链模式,其目的是组织一个对象链处理一个如方法调用的请求。
当ConcreteHandler(具体的处理程序)不知道如何满足来自Client的请求时,或它的目的不是这个时,它会委派给链中的下一个Handler(处理程序)来处理。

本文由 伯乐在线 –
Justin(李加庆)
翻译。未经许可,禁止转载!
英文出处:kamranahmedse。欢迎加入翻译组。

UML:

这个设计模式通常和复合模式一起使用,其中有些叶子或容器对象默认委派操作给它们的父对象。另一个例子是,本地化通常是使用责任链处理的,当德语翻译适配器没有为翻译关键词找到合适的结果时,就返回到英语适配器或干脆直接显示关键词本身。

用最简单的语言,解释设计模式。

图片 1

耦合减少到最低限度:Client类不知道由哪个具体的类来处理请求;在创建对象图时配置了链;ConcreteHandlers不知道哪个对象是它们的继承者。行为在对象之间分配是成功的,链中最近的对象有优先权和责任满足请求。

虽然示例代码是用 PHP7
实现的,但因为概念是一样的,所以语言并不会阻碍大家理解设计模式。

通过让多个对象都有机会处理该请求,来避免耦合请求的发送者的接收器,。**链接接收对象并且通过链来传递请求直到一个对象处理它。**

参与者: ◆Client(客户端):向Handler(处理程序)提交一个请求;
◆Handler(处理程序)抽象:接收一个请求,以某种方式满足它;
◆ConcreteHandlers(具体的处理程序):接收一个请求,设法满足它,如果不成功就委派给下一个处理程序。
下面的代码实现了一个最著名的责任链示例:多级缓存。

  • 《人人都能读懂的设计模式(1):创建型模式》
  • 《人人都能读懂的设计模式(2):结构型模式》

Avoid coupling the sender of a request to its receiver by giving more
than one object a chance to handle the request. Chain the receiving
objects and pass the request along the chain until an object handles
it. 

复制代码 代码如下:

概述

行为型设计模式关心对象之间的责任分配。与结构型设计模式不同的是,行为型设计模式不仅仅指定结构,而且还概述了它们之间的消息传递/通信的模式。或者换句话说,行为型模式帮助回答了“软件组件是如何运行的?”

Avoid coupling the sender of a request to its receiver by giving more
than one object a chance to handle the request. Chain the receiving
objects and pass the request along the chain until an object handles
it. 

/** 
 * The Handler abstraction. Objects that want to be a part of the 
 * ChainOfResponsibility must implement this interface directly or
via 
 * inheritance from an AbstractHandler. 
 */
interface KeyValueStore 

    /** 
     * Obtain a value. 
     * @param string $key 
     * @return mixed 
     */
    public function get($key); 

维基百科

在软件工程中,行为型设计模式为设计模式的一种类型,用来识别对象之间的常用交流模式并加以实现。如此,可以在交流时增强灵活性。

分类

  • 责任链模式
  • 命令模式
  • 迭代器模式
  • 中介者模式
  • 备忘录模式
  • 观察者模式
  • 访问者模式
  • 策略模式
  • 状态模式
  • 模板方法模式

 

/** 
 * Basic no-op implementation which ConcreteHandlers not interested
in 
 * caching or in interfering with the retrieval inherit from. 
 */
abstract class AbstractKeyValueStore implements KeyValueStore 

    protected $_nextHandler; 

🔗 责任链模式

  • Handler   ()
    • defines an interface for handling the requests
    • 定义一个处理请求的接口
    • (optional) implements the successor link
    • 实现successor链接
  • ConcreteHandler   ()
    • handles requests it is responsible for
    • 处理负责的请求
    • can access its successor
    • 能够访问successor 
    • if the ConcreteHandler can handle the request, it does so;
      otherwise it forwards the request to its successor
    • 如果ConcreteHandler能处理请求,它也可以.
  • Client   ()
    • initiates the request to a ConcreteHandler object on the chain  
    • 启动链上的请求

    public function get($key) 
    { 
 return $this->_nextHandler->get($key); 
    } 

现实生活示例

例如,你的帐户中有三种付款方式(A,B 和 C); 每种方式付款额不同。 A
可支付 100 美元,B 可支付 300 美元,C 可支付 1000 美元,支付的优先级为
A->B->C。现在想要购买价值 210
美元的东西。使用责任链模式,首先将检查帐户 A
是否可以进行购买,如果可以购买,链条将被破坏。如果不能购买,将继续检查账号
B
是否可以购买,如果可以购买,链条将被破坏,否则请求将继续转发,直到找到合适的处理程序。这里的
A、B 和 C 就是责任链的链条,整个现象就是责任链模式。

 

/** 
 * Ideally the last ConcreteHandler in the chain. At least, if inserted
in 
 * a Chain it will be the last node to be called. 
 */
class SlowStore implements KeyValueStore 

    /** 
     * This could be a somewhat slow store: a database or a flat
file. 
     */
    protected $_values; 

概述

责任链模式有助于建立一个对象链。请求从一端进入,在对象之间转发,直到找到合适的处理程序。

Sample:

    public function __construct(array $values = array()) 
    { 
 $this->_values = $values; 
    } 

维基百科

责任链模式是面向对象程序设计的一种软件设计模式,它包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,不能处理的命令对象传递给该链中的下一个处理对象。

程序示例

以上面的支付账号为例,首先给出账户基类,包含链接账号的逻辑以及一些不同类型的账户

abstract class Account { protected $successor; protected $balance;
public function setNext(Account $account) { $this->successor =
$account; } public function pay(float $amountToPay) { if
($this->canPay($amountToPay)) { echo sprintf(‘Paid %s using %s’ .
PHP_EOL, $amountToPay, get_called_class()); } elseif
($this->successor) { echo sprintf(‘Cannot pay using %s. Proceeding
..’ . PHP_EOL, get_called_class());
$this->successor->pay($amountToPay); } else { throw new
Exception(‘None of the accounts have enough balance’); } } public
function canPay($amount): bool { return $this->balance >= $amount;
} } class Bank extends Account { protected $balance; public function
__construct(float $balance) { $this->balance = $balance; } } class
Paypal extends Account { protected $balance; public function
__construct(float $balance) { $this->balance = $balance; } } class
Bitcoin extends Account { protected $balance; public function
__construct(float $balance) { $this->balance = $balance; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
abstract class Account
{
    protected $successor;
    protected $balance;
 
    public function setNext(Account $account)
    {
        $this->successor = $account;
    }
 
    public function pay(float $amountToPay)
    {
        if ($this->canPay($amountToPay)) {
            echo sprintf(‘Paid %s using %s’ . PHP_EOL, $amountToPay, get_called_class());
        } elseif ($this->successor) {
            echo sprintf(‘Cannot pay using %s. Proceeding ..’ . PHP_EOL, get_called_class());
            $this->successor->pay($amountToPay);
        } else {
            throw new Exception(‘None of the accounts have enough balance’);
        }
    }
 
    public function canPay($amount): bool
    {
        return $this->balance >= $amount;
    }
}
 
class Bank extends Account
{
    protected $balance;
 
    public function __construct(float $balance)
    {
        $this->balance = $balance;
    }
}
 
class Paypal extends Account
{
    protected $balance;
 
    public function __construct(float $balance)
    {
        $this->balance = $balance;
    }
}
 
class Bitcoin extends Account
{
    protected $balance;
 
    public function __construct(float $balance)
    {
        $this->balance = $balance;
    }
}

然后通过上面定义的链接(即 Bank, Paypal, Bitcoin)形成责任链

// Let’s prepare a chain like below // $bank->$paypal->$bitcoin //
// First priority bank // If bank can’t pay then paypal // If paypal
can’t pay then bit coin $bank = new Bank(100); // Bank with balance 100
$paypal = new Paypal(200); // Paypal with balance 200 $bitcoin = new
Bitcoin(300); // Bitcoin with balance 300 $bank->setNext($paypal);
$paypal->setNext($bitcoin); // Let’s try to pay using the first
priority i.e. bank $bank->pay(259); // Output will be //
============== // Cannot pay using bank. Proceeding .. // Cannot pay
using paypal. Proceeding ..: // Paid 259 using Bitcoin!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Let’s prepare a chain like below
//      $bank->$paypal->$bitcoin
//
// First priority bank
//      If bank can’t pay then paypal
//      If paypal can’t pay then bit coin
 
$bank = new Bank(100);          // Bank with balance 100
$paypal = new Paypal(200);      // Paypal with balance 200
$bitcoin = new Bitcoin(300);    // Bitcoin with balance 300
 
$bank->setNext($paypal);
$paypal->setNext($bitcoin);
 
// Let’s try to pay using the first priority i.e. bank
$bank->pay(259);
 
// Output will be
// ==============
// Cannot pay using bank. Proceeding ..
// Cannot pay using paypal. Proceeding ..:
// Paid 259 using Bitcoin!

 

    public function get($key) 
    { 
 return $this->_values[$key]; 
    } 

👮 命令模式

    abstract class Handler
    {
        protected Handler successor; 
        public void SetSuccessor(Handler successor)
        { 
            this.successor = successor; 
        } 
        public abstract void HandleRequest(int request); 
    }

/** 
 * A ConcreteHandler that handles the request for a key by looking for
it in 
 * its own cache. Forwards to the next handler in case of cache
miss. 
 */
class InMemoryKeyValueStore implements KeyValueStore 

    protected $_nextHandler; 
    protected $_cached = array(); 

现实生活示例

一个典型的例子是你在餐厅点菜,你(即客户)向服务员(即
Invoker)点餐(即命令),服务员只需将需求转达给会烹饪的厨师。
另外一个例子是你(即客户端)使用遥控器(Invoker)打开(即命令)电视机(即接收器)。

 

    public function __construct(KeyValueStore $nextHandler) 
    { 
 $this->_nextHandler = $nextHandler; 
    } 

概述

命令模式允许将操作封装在对象中,其背后的关键思想是提供客户端与接收器分离的方法。

 

    protected function _load($key) 
    { 
 if (!isset($this->_cached[$key])) { 
     $this->_cached[$key] =
$this->_nextHandler->get($key); 
 } 
    } 

维基百科

在面向对象程序设计的范畴中,命令模式是一种行为型设计模式。将所有需要的信息封装到对象中,用于之后的动作(action)或者事件触发。被封装的信息包括方法名以及拥有方法及参数的对象。

程序示例

首先给出一个接收器,实现了可能会执行的动作:

// Receiver class Bulb { public function turnOn() { echo “Bulb has been
lit”; } public function turnOff() { echo “Darkness!”; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
// Receiver
class Bulb
{
    public function turnOn()
    {
        echo "Bulb has been lit";
    }
 
    public function turnOff()
    {
        echo "Darkness!";
    }
}

然后给出一个接口,(Bulb)中的每个命令都要实现这个接口,得到一组命令集:

interface Command { public function execute(); public function undo();
public function redo(); } // Command class TurnOn implements Command {
protected $bulb; public function __construct(Bulb $bulb) {
$this->bulb = $bulb; } public function execute() {
$this->bulb->turnOn(); } public function undo() {
$this->bulb->turnOff(); } public function redo() {
$this->execute(); } } class TurnOff implements Command { protected
$bulb; public function __construct(Bulb $bulb) { $this->bulb =
$bulb; } public function execute() { $this->bulb->turnOff(); }
public function undo() { $this->bulb->turnOn(); } public function
redo() { $this->execute(); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
interface Command
{
    public function execute();
    public function undo();
    public function redo();
}
 
// Command
class TurnOn implements Command
{
    protected $bulb;
 
    public function __construct(Bulb $bulb)
    {
        $this->bulb = $bulb;
    }
 
    public function execute()
    {
        $this->bulb->turnOn();
    }
 
    public function undo()
    {
        $this->bulb->turnOff();
    }
 
    public function redo()
    {
        $this->execute();
    }
}
 
class TurnOff implements Command
{
    protected $bulb;
 
    public function __construct(Bulb $bulb)
    {
        $this->bulb = $bulb;
    }
 
    public function execute()
    {
        $this->bulb->turnOff();
    }
 
    public function undo()
    {
        $this->bulb->turnOn();
    }
 
    public function redo()
    {
        $this->execute();
    }
}

然后是Invoker,客户端将与之交互以处理各种命令:

// Invoker class RemoteControl { public function submit(Command
$command) { $command->execute(); } }

1
2
3
4
5
6
7
8
// Invoker
class RemoteControl
{
    public function submit(Command $command)
    {
        $command->execute();
    }
}

最后来看一下如何在客户端中使用:

$bulb = new Bulb(); $turnOn = new TurnOn($bulb); $turnOff = new
TurnOff($bulb); $remote = new RemoteControl();
$remote->submit($turnOn); // Bulb has been lit!
$remote->submit($turnOff); // Darkness!

1
2
3
4
5
6
7
8
$bulb = new Bulb();
 
$turnOn = new TurnOn($bulb);
$turnOff = new TurnOff($bulb);
 
$remote = new RemoteControl();
$remote->submit($turnOn); // Bulb has been lit!
$remote->submit($turnOff); // Darkness!

命令模式也可用于实现基于事务的系统。在执行命令时,需要持续保存命令的历史,如果最后一条命令成功执行,皆大欢喜,否则遍历历史记录,并对所有执行过的命执行撤销

    class ConcreteHandler1:Handler
    {
        public override void HandleRequest(int request)
        {
            if (request >= 0 && request < 10)
            { 
                Console.WriteLine("{0} handled request {1}", 
                  this.GetType().Name, request); 
            } 
            else if (successor != null)
            { 
                successor.HandleRequest(request); 
            } 
        }
    }

    public function get($key) 
    { 
 $this->_load($key); 
 return $this->_cached[$key]; 
    } 

➿ 迭代器模式

 

/** 
 * A ConcreteHandler that delegates the request without trying to 
 * understand it at all. It may be easier to use in the user
interface 
 * because it can specialize itself by defining methods that
generates 
 * html, or by addressing similar user interface concerns. 
 * Some Clients see this object only as an instance of KeyValueStore 
 * and do not care how it satisfy their requests, while other ones 
 * may use it in its entirety (similar to a class-based adapter). 
 * No client knows that a chain of Handlers exists. 
 */
class FrontEnd extends AbstractKeyValueStore 

    public function __construct(KeyValueStore $nextHandler) 
    { 
 $this->_nextHandler = $nextHandler; 
    } 

现实生活示例

老式的无线电设备将是一个很好的迭代器示例,用户可以在某个频道上启动,然后使用下一个或上一个按钮来切换频道。或者以
MP3
播放器或电视机为例,你可以按下一个按钮和上一个按钮进行连续的频道切换。换句话说,它们都提供了一个界面来遍历相应的频道,歌曲或广播电台。

    class ConcreteHandler2:Handler
    {
        public override void HandleRequest(int request)
        {
            if (request >= 10 && request < 20)
            { 
                Console.WriteLine("{0} handled request {1}", 
                  this.GetType().Name, request); 
            } 
            else if (successor != null)
            { 
                successor.HandleRequest(request); 
            } 
        }
    }

    public function getEscaped($key) 
    { 
 return htmlentities($this->get($key), ENT_NOQUOTES, ‘UTF-8’); 
    } 

概述

迭代器模式提供了一种方法,可以访问对象的元素而不暴露底层实现。

 

// Client code 
$store = new SlowStore(array(‘pd’ => ‘Philip K. Dick’, 
 ‘ia’ => ‘Isaac Asimov’, 
 ‘ac’ => ‘Arthur C. Clarke’, 
 ‘hh’ => ‘Helmut Heißenbüttel’)); 
// in development, we skip cache and pass $store directly to FrontEnd 
$cache = new InMemoryKeyValueStore($store); 
$frontEnd = new FrontEnd($cache); 

维基百科

在面向对象程序设计中,迭代器模式是一种设计模式,其中迭代器用于遍历容器并访问容器的元素。迭代器模式将算法与容器解耦;
在某些情况下,算法是特定容器必需的,因此不能解耦。

程序示例

通过PHP,使用
SPL(PHP标准库)可以轻松实现迭代器模式,以上述收音机为例,首先给出
RadioStation

class RadioStation { protected $frequency; public function
__construct(float $frequency) { $this->frequency = $frequency; }
public function getFrequency(): float { return $this->frequency; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class RadioStation
{
    protected $frequency;
 
    public function __construct(float $frequency)
    {
        $this->frequency = $frequency;
    }
 
    public function getFrequency(): float
    {
        return $this->frequency;
    }
}

然后是 迭代器

use Countable; use Iterator; class StationList implements Countable,
Iterator { /** [@var]()
RadioStation[] $stations */ protected $stations = []; /**
[@var]() int $counter */
protected $counter; public function addStation(RadioStation $station) {
$this->stations[] = $station; } public function
removeStation(RadioStation $toRemove) { $toRemoveFrequency =
$toRemove->getFrequency(); $this->stations =
array_filter($this->stations, function (RadioStation $station) use
($toRemoveFrequency) { return $station->getFrequency() !==
$toRemoveFrequency; }); } public function count(): int { return
count($this->stations); } public function current(): RadioStation {
return $this->stations[$this->counter]; } public function key()
{ return $this->counter; } public function next() {
$this->counter++; } public function rewind() { $this->counter = 0;
} public function valid(): bool { return
isset($this->stations[$this->counter]); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
use Countable;
use Iterator;
 
class StationList implements Countable, Iterator
{
    /** [@var](http://www.jobbole.com/members/variable) RadioStation[] $stations */
    protected $stations = [];
 
    /** [@var](http://www.jobbole.com/members/variable) int $counter */
    protected $counter;
 
    public function addStation(RadioStation $station)
    {
        $this->stations[] = $station;
    }
 
    public function removeStation(RadioStation $toRemove)
    {
        $toRemoveFrequency = $toRemove->getFrequency();
        $this->stations = array_filter($this->stations, function (RadioStation $station) use ($toRemoveFrequency) {
            return $station->getFrequency() !== $toRemoveFrequency;
        });
    }
 
    public function count(): int
    {
        return count($this->stations);
    }
 
    public function current(): RadioStation
    {
        return $this->stations[$this->counter];
    }
 
    public function key()
    {
        return $this->counter;
    }
 
    public function next()
    {
        $this->counter++;
    }
 
    public function rewind()
    {
        $this->counter = 0;
    }
 
    public function valid(): bool
    {
        return isset($this->stations[$this->counter]);
    }
}

可以这样使用

$stationList = new StationList(); $stationList->addStation(new
RadioStation(89)); $stationList->addStation(new RadioStation(101));
$stationList->addStation(new RadioStation(102));
$stationList->addStation(new RadioStation(103.2));
foreach($stationList as $station) { echo $station->getFrequency() .
PHP_EOL; } $stationList->removeStation(new RadioStation(89)); //
Will remove station 89

1
2
3
4
5
6
7
8
9
10
11
12
$stationList = new StationList();
 
$stationList->addStation(new RadioStation(89));
$stationList->addStation(new RadioStation(101));
$stationList->addStation(new RadioStation(102));
$stationList->addStation(new RadioStation(103.2));
 
foreach($stationList as $station) {
    echo $station->getFrequency() . PHP_EOL;
}
 
$stationList->removeStation(new RadioStation(89)); // Will remove station 89
    class ConcreteHandler3:Handler
    {
        public override void HandleRequest(int request)
        {
            if (request >= 20 && request < 30)
            { 
                Console.WriteLine("{0} handled request {1}", 
                  this.GetType().Name, request); 
            } 
            else if (successor != null)
            {
                successor.HandleRequest(request); 
            } 
        }
    }

echo $frontEnd->get(‘ia’), “\n”; 
echo $frontEnd->getEscaped(‘hh’), “\n”;

👽 中介者模式

 

关于PHP责任链设计模式的一些实现说明: ◆责任链可能已经存在于对象图中,和复合模式的例子一样;
◆此外,Handler抽象可能存在,也可能不存在,最好的选择是一个分开的Handler接口只可以执行handleRequest()操作,不要强制一个链只在一个层次中,因为后面的已经存在了;
◆也可能引入一个抽象类,但由于请求处理是一个正交关注,因此具体的类可能已经继承了其它类;
◆通过constructor
或setter,Handler(或下一个Handler)被注入到Client或前一个Handler;
◆请求对象通常是一个ValueObject,也可能被实现为一个Flyweight,在PHP中,它可能是一个标量类型,如string,注意在某些语言中,一个string就是一个不变的ValueObject。

现实生活示例

典型的例子是你通过手机与他人通话,你与通话者之间有一个网络供应商,对话将通过供应商传递而非直接传递。这种情况下网络供应商就是中介者。

            #region ChainOR
            Handler h1 = new ConcreteHandler1(); 
            Handler h2 = new ConcreteHandler2(); 
            Handler h3 = new ConcreteHandler3(); 
            h1.SetSuccessor(h2); 
            h2.SetSuccessor(h3);

            int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 }; 
            foreach (int request in requests)
            { 
                h1.HandleRequest(request); 
            } 
            #endregion

简单的总结责任链模式,可以归纳为:用一系列类(classes)试图处理一个请求request,这些类之间是一个松散的耦合,唯一共同点是在他们之间传递request.
也就是说,来了一个请求,A类先处理,如果没有处理,就传递到B类处理,如果没有处理,就传递到C类处理,就这样象一个链条(chain)一样传递下去。

概述

中介者模式添加了第三方对象(称为中介者)来控制两个对象(称为
colleague)之间的交互。中介者模式有助于减少通信类之间的耦合,因为类之间无需知道对方的实现。

 

您可能感兴趣的文章:

  • Java设计模式编程中的责任链模式使用示例
  • 详解C++设计模式编程中责任链模式的应用
  • Python使用设计模式中的责任链模式与迭代器模式的示例
  • 实例讲解Java的设计模式编程中责任链模式的运用
  • Python的组合模式与责任链模式编程示例
  • 学习JavaScript设计模式之责任链模式
  • JAVA设计模式之责任链模式详解
  • Java设计模式之责任链模式(Chain of
    Responsibility模式)介绍
  • Java设计模式之责任链模式简介
  • 轻松掌握java责任链模式

维基百科

在软件工程中,中介者模式包装了一系列对象相互作用的方式。这种模式被认为是一种行为模式,因为它可以改变程序的运行时行为。

程序示例

下面是一个最简单的用户(即
colleague)在聊天室(中介者)中互相发送消息的示例

首先给出中介者及聊天室

interface ChatRoomMediator { public function showMessage(User $user,
string $message); } // Mediator class ChatRoom implements
ChatRoomMediator { public function showMessage(User $user, string
$message) { $time = date(‘M d, y H:i’); $sender = $user->getName();
echo $time . ‘[‘ . $sender . ‘]:’ . $message; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
interface ChatRoomMediator
{
    public function showMessage(User $user, string $message);
}
 
// Mediator
class ChatRoom implements ChatRoomMediator
{
    public function showMessage(User $user, string $message)
    {
        $time = date(‘M d, y H:i’);
        $sender = $user->getName();
 
        echo $time . ‘[‘ . $sender . ‘]:’ . $message;
    }
}

然后是用户即 colleague

class User { protected $name; protected $chatMediator; public function
__construct(string $name, ChatRoomMediator $chatMediator) {
$this->name = $name; $this->chatMediator = $chatMediator; } public
function getName() { return $this->name; } public function
send($message) { $this->chatMediator->showMessage($this,
$message); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class User {
    protected $name;
    protected $chatMediator;
 
    public function __construct(string $name, ChatRoomMediator $chatMediator) {
        $this->name = $name;
        $this->chatMediator = $chatMediator;
    }
 
    public function getName() {
        return $this->name;
    }
 
    public function send($message) {
        $this->chatMediator->showMessage($this, $message);
    }
}

用法

$mediator = new ChatRoom(); $john = new User(‘John Doe’, $mediator);
$jane = new User(‘Jane Doe’, $mediator); $john->send(‘Hi there!’);
$jane->send(‘Hey!’); // Output will be // Feb 14, 10:58 [John]: Hi
there! // Feb 14, 10:58 [Jane]: Hey!

1
2
3
4
5
6
7
8
9
10
11
$mediator = new ChatRoom();
 
$john = new User(‘John Doe’, $mediator);
$jane = new User(‘Jane Doe’, $mediator);
 
$john->send(‘Hi there!’);
$jane->send(‘Hey!’);
 
// Output will be
// Feb 14, 10:58 [John]: Hi there!
// Feb 14, 10:58 [Jane]: Hey!

 

💾 备忘录模式

 

现实生活示例

以计算器(即发起者)为例,每当执行一些计算时,最后一次计算结果将保存在内存中(即备忘录),以便数据可以恢复,也可以使用某些操作按钮(即临时代理)来恢复数据。

 

概述

备忘录模式以一种稍后可平滑恢复的方式捕捉并存储对象的当前状态。

 

维基百科

备忘录模式是一种软件设计模式,可以将对象恢复到之前的状态(通过回滚来撤销)

需要提供撤销操作时,备忘录模式通常很有用。

程序示例

首先给出可以存储编辑器状态的备忘录对象

class EditorMemento { protected $content; public function
__construct(string $content) { $this->content = $content; } public
function getContent() { return $this->content; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class EditorMemento
{
    protected $content;
 
    public function __construct(string $content)
    {
        $this->content = $content;
    }
 
    public function getContent()
    {
        return $this->content;
    }
}

然后是使用备忘录对象的编辑器及发起者

class Editor { protected $content = ”; public function type(string
$words) { $this->content = $this->content . ‘ ‘ . $words; } public
function getContent() { return $this->content; } public function
save() { return new EditorMemento($this->content); } public function
restore(EditorMemento $memento) { $this->content =
$memento->getContent(); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Editor
{
    protected $content = ”;
 
    public function type(string $words)
    {
        $this->content = $this->content . ‘ ‘ . $words;
    }
 
    public function getContent()
    {
        return $this->content;
    }
 
    public function save()
    {
        return new EditorMemento($this->content);
    }
 
    public function restore(EditorMemento $memento)
    {
        $this->content = $memento->getContent();
    }
}

这样使用

$editor = new Editor(); // Type some stuff $editor->type(‘This is the
first sentence.’); $editor->type(‘This is second.’); // Save the
state to restore to : This is the first sentence. This is second. $saved
= $editor->save(); // Type some more $editor->type(‘And this is
third.’); // Output: Content before Saving echo
$editor->getContent(); // This is the first sentence. This is second.
And this is third. // Restoring to last saved state
$editor->restore($saved); $editor->getContent(); // This is the
first sentence. This is second.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$editor = new Editor();
 
// Type some stuff
$editor->type(‘This is the first sentence.’);
$editor->type(‘This is second.’);
 
// Save the state to restore to : This is the first sentence. This is second.
$saved = $editor->save();
 
// Type some more
$editor->type(‘And this is third.’);
 
// Output: Content before Saving
echo $editor->getContent(); // This is the first sentence. This is second. And this is third.
 
// Restoring to last saved state
$editor->restore($saved);
 
$editor->getContent(); // This is the first sentence. This is second.

 

😎 观察者模式

 

现实生活示例

一个很好的例子是,求职者订阅了一些招聘网站,每当有匹配的工作机会时,求职者就会收到通知。

 

概述

定义了对象之间的依赖,一旦其中一个对象的状态发生改变,依赖它的对象都会收到通知。

 

维基百科

观察者模式是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。通常通过调用目标对象所提供的方法来实现。

程序示例

以上述求职订阅为例,首先给出求职者,有职位发布时会收到通知

class JobPost { protected $title; public function __construct(string
$title) { $this->title = $title; } public function getTitle() {
return $this->title; } } class JobSeeker implements Observer {
protected $name; public function __construct(string $name) {
$this->name = $name; } public function onJobPosted(JobPost $job) { //
Do something with the job posting echo ‘Hi ‘ . $this->name . ‘! New
job posted: ‘. $job->getTitle(); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class JobPost
{
    protected $title;
 
    public function __construct(string $title)
    {
        $this->title = $title;
    }
 
    public function getTitle()
    {
        return $this->title;
    }
}
 
class JobSeeker implements Observer
{
    protected $name;
 
    public function __construct(string $name)
    {
        $this->name = $name;
    }
 
    public function onJobPosted(JobPost $job)
    {
        // Do something with the job posting
        echo ‘Hi ‘ . $this->name . ‘! New job posted: ‘. $job->getTitle();
    }
}

然后是求职者订阅的职位发布类

class JobPostings implements Observable { protected $observers = [];
protected function notify(JobPost $jobPosting) { foreach
($this->observers as $observer) {
$observer->onJobPosted($jobPosting); } } public function
attach(Observer $observer) { $this->observers[] = $observer; }
public function addJob(JobPost $jobPosting) {
$this->notify($jobPosting); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class JobPostings implements Observable
{
    protected $observers = [];
 
    protected function notify(JobPost $jobPosting)
    {
        foreach ($this->observers as $observer) {
            $observer->onJobPosted($jobPosting);
        }
    }
 
    public function attach(Observer $observer)
    {
        $this->observers[] = $observer;
    }
 
    public function addJob(JobPost $jobPosting)
    {
        $this->notify($jobPosting);
    }
}

这样使用

// Create subscribers $johnDoe = new JobSeeker(‘John Doe’); $janeDoe =
new JobSeeker(‘Jane Doe’); // Create publisher and attach subscribers
$jobPostings = new JobPostings(); $jobPostings->attach($johnDoe);
$jobPostings->attach($janeDoe); // Add a new job and see if
subscribers get notified $jobPostings->addJob(new JobPost(‘Software
Engineer’)); // Output // Hi John Doe! New job posted: Software Engineer
// Hi Jane Doe! New job posted: Software Engineer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Create subscribers
$johnDoe = new JobSeeker(‘John Doe’);
$janeDoe = new JobSeeker(‘Jane Doe’);
 
// Create publisher and attach subscribers
$jobPostings = new JobPostings();
$jobPostings->attach($johnDoe);
$jobPostings->attach($janeDoe);
 
// Add a new job and see if subscribers get notified
$jobPostings->addJob(new JobPost(‘Software Engineer’));
 
// Output
// Hi John Doe! New job posted: Software Engineer
// Hi Jane Doe! New job posted: Software Engineer

 

🏃 访问者模式

 

现实生活示例

假如有人前往迪拜,他们需要有证件(比如签证)就可进入迪拜。到达后,无需获得许可或做一些跑腿工作,他们便可以自由前往迪拜的任何地方;
只要是知道的地方,就能游览。访问者模式可以做到这一点,它可以帮助你添加访问地点,以便在无需跑腿的情况下,可以尽可能多地访问。

概述

访问者模式可以在无需修改对象的情况下增加一些额外操作。

维基百科

在面向对象编程和软件工程中,访问者设计模式是一种从对象结构中分离算法的方式。这种分离的实际结果是能够向现有的对象结构添加新的操作,而无需修改这些结构。这是遵循开放/封闭原则的一种方式。

编程示例

以模拟动物园为例,动物园里有几种不同种类的动物,我们需要让它们发出叫声,下面使用访问者模式实现

// Visitee interface Animal { public function accept(AnimalOperation
$operation); } // Visitor interface AnimalOperation { public function
visitMonkey(Monkey $monkey); public function visitLion(Lion $lion);
public function visitDolphin(Dolphin $dolphin); }

1
2
3
4
5
6
7
8
9
10
11
12
13
// Visitee
interface Animal
{
    public function accept(AnimalOperation $operation);
}
 
// Visitor
interface AnimalOperation
{
    public function visitMonkey(Monkey $monkey);
    public function visitLion(Lion $lion);
    public function visitDolphin(Dolphin $dolphin);
}

然后实现各种动物

class Monkey implements Animal { public function shout() { echo ‘Ooh oo
aa aa!’; } public function accept(AnimalOperation $operation) {
$operation->visitMonkey($this); } } class Lion implements Animal {
public function roar() { echo ‘Roaaar!’; } public function
accept(AnimalOperation $operation) { $operation->visitLion($this); }
} class Dolphin implements Animal { public function speak() { echo ‘Tuut
tuttu tuutt!’; } public function accept(AnimalOperation $operation) {
$operation->visitDolphin($this); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Monkey implements Animal
{
    public function shout()
    {
        echo ‘Ooh oo aa aa!’;
    }
 
    public function accept(AnimalOperation $operation)
    {
        $operation->visitMonkey($this);
    }
}
 
class Lion implements Animal
{
    public function roar()
    {
        echo ‘Roaaar!’;
    }
 
    public function accept(AnimalOperation $operation)
    {
        $operation->visitLion($this);
    }
}
 
class Dolphin implements Animal
{
    public function speak()
    {
        echo ‘Tuut tuttu tuutt!’;
    }
 
    public function accept(AnimalOperation $operation)
    {
        $operation->visitDolphin($this);
    }
}

接下来实现访问者

class Speak implements AnimalOperation { public function
visitMonkey(Monkey $monkey) { $monkey->shout(); } public function
visitLion(Lion $lion) { $lion->roar(); } public function
visitDolphin(Dolphin $dolphin) { $dolphin->speak(); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Speak implements AnimalOperation
{
    public function visitMonkey(Monkey $monkey)
    {
        $monkey->shout();
    }
 
    public function visitLion(Lion $lion)
    {
        $lion->roar();
    }
 
    public function visitDolphin(Dolphin $dolphin)
    {
        $dolphin->speak();
    }
}

可以这样使用

$monkey = new Monkey(); $lion = new Lion(); $dolphin = new Dolphin();
$speak = new Speak(); $monkey->accept($speak); // Ooh oo aa aa!
$lion->accept($speak); // Roaaar! $dolphin->accept($speak); //
Tuut tutt tuutt!

1
2
3
4
5
6
7
8
9
$monkey = new Monkey();
$lion = new Lion();
$dolphin = new Dolphin();
 
$speak = new Speak();
 
$monkey->accept($speak);    // Ooh oo aa aa!    
$lion->accept($speak);      // Roaaar!
$dolphin->accept($speak);   // Tuut tutt tuutt!

当需要为动物添加新动作时,我们本可以通过动物支持继承来实现,但是需要修改动物类。但现在就不必修改动物类了。例如,假设需要向动物添加跳跃行为,我们可以通过创建一个新的访问者来简单地添加此行为,即:

class Jump implements AnimalOperation { public function
visitMonkey(Monkey $monkey) { echo ‘Jumped 20 feet high! on to the
tree!’; } public function visitLion(Lion $lion) { echo ‘Jumped 7 feet!
Back on the ground!’; } public function visitDolphin(Dolphin $dolphin) {
echo ‘Walked on water a little and disappeared’; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Jump implements AnimalOperation
{
    public function visitMonkey(Monkey $monkey)
    {
        echo ‘Jumped 20 feet high! on to the tree!’;
    }
 
    public function visitLion(Lion $lion)
    {
        echo ‘Jumped 7 feet! Back on the ground!’;
    }
 
    public function visitDolphin(Dolphin $dolphin)
    {
        echo ‘Walked on water a little and disappeared’;
    }
}

这样使用

$jump = new Jump(); $monkey->accept($speak); // Ooh oo aa aa!
$monkey->accept($jump); // Jumped 20 feet high! on to the tree!
$lion->accept($speak); // Roaaar! $lion->accept($jump); // Jumped
7 feet! Back on the ground! $dolphin->accept($speak); // Tuut tutt
tuutt! $dolphin->accept($jump); // Walked on water a little and
disappeared

1
2
3
4
5
6
7
8
9
10
$jump = new Jump();
 
$monkey->accept($speak);   // Ooh oo aa aa!
$monkey->accept($jump);    // Jumped 20 feet high! on to the tree!
 
$lion->accept($speak);     // Roaaar!
$lion->accept($jump);      // Jumped 7 feet! Back on the ground!
 
$dolphin->accept($speak);  // Tuut tutt tuutt!
$dolphin->accept($jump);   // Walked on water a little and disappeared

💡 策略模式

现实生活示例

考虑排序的例子,我们实现了冒泡排序,但数据开始增长,冒泡排序开始变得非常慢。为了解决这个问题,我们实现了快速排序。尽管快速排序算法对于大型数据集来说效果很好,但对于较小的数据集却非常慢。为了解决这个问题,我们实施了一个策略,小数据集使用冒泡排序,大数据集使用快速排序。

概述

策略模式允许你基于场景转换算法或策略。

维基百科

在计算机编程中,策略模式是一种行为设计模式,可以在运行时选择算法的行为。

编程示例

以上述排序为例,首先给出策略接口及不同的策略实现

interface SortStrategy { public function sort(array $dataset): array; }
class BubbleSortStrategy implements SortStrategy { public function
sort(array $dataset): array { echo “Sorting using bubble sort”; // Do
sorting return $dataset; } } class QuickSortStrategy implements
SortStrategy { public function sort(array $dataset): array { echo
“Sorting using quick sort”; // Do sorting return $dataset; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
interface SortStrategy
{
    public function sort(array $dataset): array;
}
 
class BubbleSortStrategy implements SortStrategy
{
    public function sort(array $dataset): array
    {
        echo "Sorting using bubble sort";
 
        // Do sorting
        return $dataset;
    }
}
 
class QuickSortStrategy implements SortStrategy
{
    public function sort(array $dataset): array
    {
        echo "Sorting using quick sort";
 
        // Do sorting
        return $dataset;
    }
}

客户端可以使用任意策略

class Sorter { protected $sorter; public function
__construct(SortStrategy $sorter) { $this->sorter = $sorter; }
public function sort(array $dataset): array { return
$this->sorter->sort($dataset); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Sorter
{
    protected $sorter;
 
    public function __construct(SortStrategy $sorter)
    {
        $this->sorter = $sorter;
    }
 
    public function sort(array $dataset): array
    {
        return $this->sorter->sort($dataset);
    }
}

用法

$dataset = [1, 5, 4, 3, 2, 8]; $sorter = new Sorter(new
BubbleSortStrategy()); $sorter->sort($dataset); // Output : Sorting
using bubble sort $sorter = new Sorter(new QuickSortStrategy());
$sorter->sort($dataset); // Output : Sorting using quick sort

1
2
3
4
5
6
7
$dataset = [1, 5, 4, 3, 2, 8];
 
$sorter = new Sorter(new BubbleSortStrategy());
$sorter->sort($dataset); // Output : Sorting using bubble sort
 
$sorter = new Sorter(new QuickSortStrategy());
$sorter->sort($dataset); // Output : Sorting using quick sort

💢 状态模式

现实生活示例

想象一下,你正在使用一些绘图应用程序,你可以选择笔刷来绘画,刷子根据所选颜色改变其行为,即如果选择红色,它将绘制为红色,如果选择蓝色,那么它将绘制蓝色等。

概述

当状态改变时,类的行为也发生改变。

维基百科

状态模式是以面向对象的方式实现状态机的行为设计模式。对于状态模式,通过将每个单独状态实现为派生类的状态模式接口,
来实现一个状态机,并通过调用模式超类的方法来实现状态转换。状态模式可以被解释为一种策略模式,它能够通过调用模式接口定义的方法来切换当前策略。

程序示例

以文本编辑器为例,编辑器可以改变文本的状态如选中粗体,就会以粗体输入文本,选中斜体便以斜体输入。

首先是状态接口和一些状态实现

interface WritingState { public function write(string $words); } class
UpperCase implements WritingState { public function write(string $words)
{ echo strtoupper($words); } } class LowerCase implements WritingState {
public function write(string $words) { echo strtolower($words); } }
class Default implements WritingState { public function write(string
$words) { echo $words; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
interface WritingState
{
    public function write(string $words);
}
 
class UpperCase implements WritingState
{
    public function write(string $words)
    {
        echo strtoupper($words);
    }
}
 
class LowerCase implements WritingState
{
    public function write(string $words)
    {
        echo strtolower($words);
    }
}
 
class Default implements WritingState
{
    public function write(string $words)
    {
        echo $words;
    }
}

然后是文本编辑器

class TextEditor { protected $state; public function
__construct(WritingState $state) { $this->state = $state; } public
function setState(WritingState $state) { $this->state = $state; }
public function type(string $words) { $this->state->write($words);
} }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class TextEditor
{
    protected $state;
 
    public function __construct(WritingState $state)
    {
        $this->state = $state;
    }
 
    public function setState(WritingState $state)
    {
        $this->state = $state;
    }
 
    public function type(string $words)
    {
        $this->state->write($words);
    }
}

用法

$editor = new TextEditor(new Default()); $editor->type(‘First line’);
$editor->setState(new UpperCase()); $editor->type(‘Second line’);
$editor->type(‘Third line’); $editor->setState(new LowerCase());
$editor->type(‘Fourth line’); $editor->type(‘Fifth line’); //
Output: // First line // SECOND LINE // THIRD LINE // fourth line //
fifth line

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$editor = new TextEditor(new Default());
 
$editor->type(‘First line’);
 
$editor->setState(new UpperCase());
 
$editor->type(‘Second line’);
$editor->type(‘Third line’);
 
$editor->setState(new LowerCase());
 
$editor->type(‘Fourth line’);
$editor->type(‘Fifth line’);
 
// Output:
// First line
// SECOND LINE
// THIRD LINE
// fourth line
// fifth line

📒 模板方法模式

现实生活示例

假设我们要造一座房子,建造的大体步骤如下:

  • 打地基
  • 垒墙
  • 封顶
  • 铺地板

这些步骤的顺序不能被打乱,比如说,你不能在垒墙之前先封顶。但是其中的每一步可以定制,比如墙的材料可以使用木头、聚酯纤维或者石头。

概述

模板方法模式定义了如何执行某种算法的框架,但是将这些步骤的实现推迟到子类中。

维基百科

在软件工程中,模板方法模式是一种行为设计模式,用于定义操作中算法的程序框架,将一些步骤推迟到子类实现。它允许在不改变算法结构的情况下重新定义算法的某些步骤。

程序示例

假如我们有一个构建工具,可以帮助我们测试,构建并生成构建报告(即代码覆盖报告,linting报告等),并将应用程序部署到测试服务器上。

首先是用于确定构建算法框架的基类

abstract class Builder { // Template method final public function
build() { $this->test(); $this->lint(); $this->assemble();
$this->deploy(); } abstract public function test(); abstract public
function lint(); abstract public function assemble(); abstract public
function deploy(); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
abstract class Builder
{
 
    // Template method
    final public function build()
    {
        $this->test();
        $this->lint();
        $this->assemble();
        $this->deploy();
    }
 
    abstract public function test();
    abstract public function lint();
    abstract public function assemble();
    abstract public function deploy();
}

然后提供一些基类的实现

class AndroidBuilder extends Builder { public function test() { echo
‘Running android tests’; } public function lint() { echo ‘Linting the
android code’; } public function assemble() { echo ‘Assembling the
android build’; } public function deploy() { echo ‘Deploying android
build to server’; } } class IosBuilder extends Builder { public function
test() { echo ‘Running ios tests’; } public function lint() { echo
‘Linting the ios code’; } public function assemble() { echo ‘Assembling
the ios build’; } public function deploy() { echo ‘Deploying ios build
to server’; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class AndroidBuilder extends Builder
{
    public function test()
    {
        echo ‘Running android tests’;
    }
 
    public function lint()
    {
        echo ‘Linting the android code’;
    }
 
    public function assemble()
    {
        echo ‘Assembling the android build’;
    }
 
    public function deploy()
    {
        echo ‘Deploying android build to server’;
    }
}
 
class IosBuilder extends Builder
{
    public function test()
    {
        echo ‘Running ios tests’;
    }
 
    public function lint()
    {
        echo ‘Linting the ios code’;
    }
 
    public function assemble()
    {
        echo ‘Assembling the ios build’;
    }
 
    public function deploy()
    {
        echo ‘Deploying ios build to server’;
    }
}

用法

$androidBuilder = new AndroidBuilder(); $androidBuilder->build(); //
Output: // Running android tests // Linting the android code //
Assembling the android build // Deploying android build to server
$iosBuilder = new IosBuilder(); $iosBuilder->build(); // Output: //
Running ios tests // Linting the ios code // Assembling the ios build //
Deploying ios build to server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$androidBuilder = new AndroidBuilder();
$androidBuilder->build();
 
// Output:
// Running android tests
// Linting the android code
// Assembling the android build
// Deploying android build to server
 
$iosBuilder = new IosBuilder();
$iosBuilder->build();
 
// Output:
// Running ios tests
// Linting the ios code
// Assembling the ios build
// Deploying ios build to server

打赏支持我翻译更多好文章,谢谢!

打赏译者

打赏支持我翻译更多好文章,谢谢!

图片 2

1 赞 3 收藏 1
评论

关于作者:Justin(李加庆)

图片 3

Python工程师一枚,对go、docker感兴趣,还在成长ing~~
个人主页 ·
我的文章 ·
15

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 澳门新葡亰官网app 版权所有