php设计模式(四):行为型模式

一、什么是行为型模式?
行为型模式就是描述类和对象之间的通信和职责的。简而言之,就是类和对象扮演什么角色,还有怎么扮演这个角色的问题。

二、行为型模式的种类
大体上分为三个大类:常见模式、已知模式、深度模式
1、常见模式包括: 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、状态模式、职责链模式、策略模式
2、 已知模式包括:备忘录模式
3、深度模式包括:解释器模式 访问者模式

下面来介绍常见模式
Ø 常见模式
1、模版方法模式(Template):
定义一个操作中的算法骨架,而将一些实现步骤延迟到子类当中实现。 就像一个豆浆机,不管放进去的是红豆还是黑豆,出来的都是豆浆。
好处:扩展性好,封装不变的代码,扩展可变的代码。
弊端:灵活性差,不能改变骨架部分。
应用场景:一类或一组具有共性的事物中。

代码实现

  1     /**
  2      *
  3      * 模板方法模式 Template
  4      *
  5      */
  6
  7     function output($string) {
  8         echo    $string . "n";
  9     }
 10
 11     class Request {
 12
 13         public $token = ‘‘;
 14
 15         public function __construct() {
 16             $this->token    = ‘0c6b7289f5334ed2b697dd461eaf9812‘;
 17         }
 18
 19     }
 20
 21     class Response {
 22
 23         public function render($content) {
 24             output(sprintf(‘response-render: %s‘, $content));
 25         }
 26
 27         public function redirect($uri) {
 28             output(sprintf(‘response-redirect: %s‘, $uri));
 29         }
 30
 31         public function json($data) {
 32             output(sprintf(‘response-data: %s‘, json_encode($data)));
 33         }
 34
 35     }
 36
 37      //父类,抽象类
 38     abstract class Controller{
 39         //封装了输入输出
 40         protected $request;
 41         protected $response;
 42
 43         //返回数据
 44         protected $data = ‘data‘;
 45
 46         public function __construct($request, $response){
 47             $this->request = $request;
 48             $this->response = $response;
 49         }
 50
 51         //执行请求函数,定义总体算法(template method),final防止被复写(不允许子类改变总体算法)
 52         public final function execute(){
 53             $this->before();
 54             if ($this->valid()){
 55                 $this->handleRequest();
 56             }
 57             $this->after();
 58         }
 59
 60         //定义hook method before,做一些具体请求的前置处理
 61         //非abstract方法,子类可以选择覆盖或不覆盖,默认什么都不做
 62         protected function before(){
 63
 64         }
 65
 66         //定义hook method valid,做请求的数据验证
 67         //非abstract方法,子类可以选择覆盖或不覆盖,默认返回验证通过
 68         protected function valid(){
 69             return true;
 70         }
 71
 72         //定义hook method handleRequest,处理请求
 73         //定义为abstract方法,子类必须实现或也声明为抽象方法(由子类的子类负责实现)
 74         abstract function handleRequest();
 75
 76         //定义hook method after,做一些请求的后置处理
 77         //非abstract方法,子类可以选择覆盖或不覆盖,默认直接输出数据
 78         protected function after(){
 79             $this->response->render($this->data);
 80         }
 81     }
 82
 83     //子类1,实现父类开放的具体算法
 84     class User extends Controller{
 85         //覆盖before方法,实现具体算法,这是一个处理用户数据操作的控制器
 86         //因此,我们选择在before里面判断用户是否已经登录了,这里简单判断下session数据
 87         function before(){
 88             if (empty($_SESSION[‘auth‘])){
 89                 //没登录就直接跳转了,不再执行后续的操作
 90                 $this->response->redirect("user/login.php");
 91             }
 92         }
 93
 94         //覆盖valid方法,这里我们验证用户提交数据中有没有带验证token
 95         function valid(){
 96             if (isset($this->request->token)){
 97                 return true;
 98             }
 99             return false;
100         }
101
102         //覆盖handleRequest方法,必选,以为父类中声明了abstract了
103         function handleRequest(){
104             //做具体处理,一般根据参数执行不同的业务逻辑
105         }
106
107         //这个类我们选择不覆盖after方法,使用默认处理方式
108     }
109
110     //子类2,实现父类开放的具体算法
111     class Post extends Controller{
112         //这个类我们选择不覆盖before方法,使用默认处理方式
113
114         //这个类我们选择不覆盖valid方法,使用默认处理方式
115
116         //覆盖handleRequest方法,必选,以为父类中声明了abstract了
117         function handleRequest(){
118             //做具体处理,一般根据参数执行不同的业务逻辑
119             $this->data = array(‘title‘ => ‘ucai‘);
120         }
121
122         //覆盖after方法,使用json格式输出数据
123         function after(){
124             $this->response->json($this->data);
125         }
126     }
127
128
129
130     class Client {
131
132         public static function test(){
133
134             $request        = new Request();
135             $response       = new Response();
136
137             //最终调用
138             $user = new User($request, $response);
139             $user->execute();
140
141
142             //最终调用
143             $post = new Post($request, $response);
144             $post->execute();
145
146         }
147
148     }
149
150     Client::test();

2、命令模式(Command) :
行为请求者与行为实现者解耦。就像军队里的“敬礼”,不管是谁听到 这个命令都会做出标准的敬礼动作。
好处:便于添加和修改行为,便于聚合多个命令。
弊端:造成过多具体的命令类。
应用场景:对要操作的对象,进行的相同操作。

代码实现

  1     /**
  2      *
  3      * 命令模式 Command
  4      *
  5      */
  6
  7     function output($string) {
  8         echo    $string . "n";
  9     }
 10
 11     class Document {
 12
 13         private $name = ‘‘;
 14
 15         public function __construct($name) {
 16             $this->name = $name;
 17         }
 18
 19         public function showText() {
 20             output(sprintf("showText: %s", $this->name));
 21         }
 22
 23         public function undo() {
 24             output(sprintf("undo-showText: %s", $this->name));
 25         }
 26
 27     }
 28
 29     class Graphics {
 30
 31         private $name = ‘‘;
 32
 33         public function __construct($name) {
 34             $this->name = $name;
 35         }
 36
 37         public function drawCircle() {
 38             output(sprintf("drawCircle: %s", $this->name));
 39         }
 40
 41         public function undo() {
 42             output(sprintf("undo-drawCircle: %s", $this->name));
 43         }
 44
 45     }
 46
 47     class Client {
 48
 49         public static function test() {
 50
 51             $document       = new Document(‘A‘);
 52             $graphics       = new Graphics(‘B‘);
 53
 54             $document->showText();
 55             $graphics->drawCircle();
 56
 57             $document->undo();
 58
 59         }
 60
 61     }
 62
 63     Client::test();
 64
 65
 66     <?php
 67
 68     /*
 69     *
 70      * 命令模式 Command
 71      *
 72      */
 73
 74     function output($string) {
 75         echo    $string . "n";
 76     }
 77
 78     interface Command {
 79         public function execute();
 80         public function undo();
 81     }
 82
 83     class Document implements Command {
 84
 85         private $name = ‘‘;
 86
 87         public function __construct($name) {
 88             $this->name = $name;
 89         }
 90
 91         public function execute() {
 92             output(sprintf("showText: %s", $this->name));
 93         }
 94
 95         public function undo() {
 96             output(sprintf("undo-showText: %s", $this->name));
 97         }
 98
 99     }
100
101     class Graphics implements Command {
102
103         private $name = ‘‘;
104
105         public function __construct($name) {
106             $this->name = $name;
107         }
108
109         public function execute() {
110             output(sprintf("drawCircle: %s", $this->name));
111         }
112
113         public function undo() {
114             output(sprintf("undo-drawCircle: %s", $this->name));
115         }
116
117     }
118
119     class Client {
120
121         public static function test() {
122
123             $array          = array();
124
125             array_push($array, new Document(‘A‘));
126             array_push($array, new Document(‘B‘));
127             array_push($array, new Graphics(‘C‘));
128             array_push($array, new Graphics(‘D‘));
129
130             foreach ($array as $command) {
131                 $command->execute();
132             }
133
134             $top            = array_pop($array);
135             $top->undo();
136
137         }
138
139     }
140
141     Client::test();
142
143
144     <?php
145
146     /**
147      *
148      * 命令模式 Command
149      *
150      */
151
152     function output($string) {
153         echo    $string . "n";
154     }
155
156     interface Command {
157         public function execute();
158         public function undo();
159     }
160
161     class Document {
162
163         private $name = ‘‘;
164
165         public function __construct($name) {
166             $this->name = $name;
167         }
168
169         public function showText() {
170             output(sprintf("showText: %s", $this->name));
171         }
172
173         public function undo() {
174             output(sprintf("undo-showText: %s", $this->name));
175         }
176
177     }
178
179     class Graphics {
180
181         private $name = ‘‘;
182
183         public function __construct($name) {
184             $this->name = $name;
185         }
186
187         public function drawCircle() {
188             output(sprintf("drawCircle: %s", $this->name));
189         }
190
191         public function undo() {
192             output(sprintf("undo-drawCircle: %s", $this->name));
193         }
194
195     }
196
197     class DocumentCommand implements Command {
198
199         private $obj = ‘‘;
200
201         public function __construct(Document $document) {
202             $this->obj = $document;
203         }
204
205         public function execute() {
206             $this->obj->showText();
207         }
208
209         public function undo() {
210             $this->obj->undo();
211         }
212
213     }
214
215     class GraphicsCommand implements Command {
216
217         private $obj = ‘‘;
218
219         public function __construct(Graphics $graphics) {
220             $this->obj = $graphics;
221         }
222
223         public function execute() {
224             $this->obj->drawCircle();
225         }
226
227         public function undo() {
228             $this->obj->undo();
229         }
230
231     }
232
233
234     class Client {
235
236         public static function test() {
237
238             $array          = array();
239
240             array_push($array, new DocumentCommand(new Document(‘A‘)));
241             array_push($array, new DocumentCommand(new Document(‘B‘)));
242             array_push($array, new GraphicsCommand(new Graphics(‘C‘)));
243             array_push($array, new GraphicsCommand(new Graphics(‘D‘)));
244
245             foreach ($array as $command) {
246                 $command->execute();
247             }
248
249             $top            = array_pop($array);
250             $top->undo();
251
252         }
253
254     }
255
256     Client::test();

3、迭代器模式(Iterator):
访问聚合对象内容而不暴露内部结构。就像一个双色球彩票开奖一 样,每次都是摇出七个球,不能能摇不是七个球的中奖号码组合。
好处:以不同方式遍历一个集合。
弊端:每次遍历都是整个集合,不能单独取出元素。
应用场景:需要操作集合里的全部元素。

代码实现

  1     /**
  2      *
  3      * 迭代器模式 Iterator
  4      *
  5      */
  6
  7     function output($string) {
  8         echo    $string . "n";
  9     }
 10
 11     class RecordIterator implements Iterator{
 12
 13         private $position = 0;
 14
 15         //注意:被迭代对象属性是私有的
 16         private $records = array();
 17
 18         public function __construct(Array $records) {
 19             $this->position = 0;
 20             $this->records = $records;
 21         }
 22
 23         function rewind() {
 24             $this->position = 0;
 25         }
 26
 27         function current() {
 28             return $this->records[$this->position];
 29         }
 30
 31         function key() {
 32             return $this->position;
 33         }
 34
 35         function next() {
 36             ++$this->position;
 37         }
 38
 39         function valid() {
 40             return isset($this->records[$this->position]);
 41         }
 42     }
 43
 44     class PostListPager {
 45
 46         protected $record   = array();
 47         protected $total    = 0;
 48         protected $page     = 0;
 49         protected $size     = 0;
 50
 51         public function __construct($category, $page, $size) {
 52
 53             $this->page     = $page;
 54             $this->size     = $size;
 55
 56             // query db
 57
 58             $total          = 28;
 59             $this->total    = $total;
 60
 61             $record     = array(
 62                             0 => array(‘id‘ => ‘1‘),
 63                             1 => array(‘id‘ => ‘2‘),
 64                             2 => array(‘id‘ => ‘3‘),
 65                             3 => array(‘id‘ => ‘4‘),
 66                         );
 67
 68             //
 69             $this->record   = $record;
 70
 71         }
 72
 73         public function getIterator() {
 74             return  new RecordIterator($this->record);
 75         }
 76
 77         public function getMaxPage() {
 78             $max    = intval($this->total / $this->size);
 79             return  $max;
 80         }
 81
 82         public function getPrevPage() {
 83             return  max($this->page - 1, 1);
 84         }
 85
 86         public function getNextPage() {
 87             return  min($this->page + 1, $this->getMaxPage());
 88         }
 89
 90     }
 91
 92     class Client {
 93
 94         public static function test(){
 95
 96             $pager      = new PostListPager(1, 2, 4);
 97
 98             foreach ($pager->getIterator() as $key => $val) {
 99                 output(sprintf(‘Key[%d],Val[%s]‘, $key, json_encode($val)));
100             }
101
102             output(sprintf(‘MaxPage[%d]‘, $pager->getMaxPage()));
103             output(sprintf(‘Prev[%d]‘, $pager->getPrevPage()));
104             output(sprintf(‘Next[%d]‘, $pager->getNextPage()));
105
106             $iterator       = $pager->getIterator();
107             while($iterator->valid()){
108                 print_r($iterator->current());
109                 $iterator->next();
110             }
111             $iterator->rewind();
112
113         }
114
115     }
116
117     Client::test();

4、观察者模式(Observer):
又叫发布订阅模式,当一个主体对象发生改变时,依赖它的多个观察
者对象都得到通知并自动更新响应。就像报社一样,今天发布的消息只要
是看这份报纸的人看到的都是同样的内容。如果发布另一份报纸,也是一 样的。
好处:广播式通信,范围大一呼百应,便于操作一个组团,“公有制”。
弊端:不能单独操作组团里的个体,不能实行按需分配。
应用场景:操作多个对象,并操作相同。

代码实现

  1     /**
  2      *
  3      * 观察者模式 Observer
  4      *
  5      */
  6
  7     function output($string) {
  8         echo    $string . "n";
  9     }
 10
 11
 12     //订单数据对象简单模拟,这个是实际需要被观察的对象(Subject),但是我们将其独立,然后
 13     //通过构造方法传入到我们模式中的Subject中,这样使具体业务更加独立
 14     class Order{
 15         //订单号
 16         private $id = ‘‘;
 17
 18         //用户ID
 19         private $userId = ‘‘;
 20
 21         //用户名
 22         private $userName = ‘‘;
 23
 24         //价格
 25         private $price = ‘‘;
 26
 27         //下单时间
 28         private $orderTime = ‘‘;
 29
 30         //订单数据填充简单模拟,实际应用中可能会读取用户表单输入并处理
 31         public function __set($name, $value){
 32             if (isset($this->$name)){
 33                 $this->$name = $value;
 34             }
 35         }
 36
 37         //获取订单属性
 38         public function __get($name){
 39             if (isset($this->$name)){
 40                 return $this->$name;
 41             }
 42             return "";
 43         }
 44     }
 45
 46     //假设的DB类,便于测试,实际会存入真实数据库
 47     class FakeDB{
 48         public function save($data){
 49             return true;
 50         }
 51     }
 52
 53
 54     class Client {
 55
 56         public static function test() {
 57
 58             //初始化一个订单数据
 59             $order = new Order();
 60             $order->id = 1001;
 61             $order->userId = 9527;
 62             $order->userName = "God";
 63             $order->price = 20.0;
 64             $order->orderTime = time();
 65
 66             //向数据库保存订单
 67             $db = new FakeDB();
 68             $result = $db->save($order);
 69             if ($result){
 70
 71                 //实际应用可能会写到日志文件中,这里直接输出
 72                 output( "[OrderId:{$order->id}] [UseId:{$order->userId}] [Price:{$order->price}]" );
 73
 74                 //实际应用会调用邮件发送服务如sendmail,这里直接输出
 75                 output( "Dear {$order->userName}: Your order {$order->id} was confirmed!" );
 76
 77                 //实际应用会调用邮件发送服务如sendmail,这里直接输出
 78                 output( "Dear Manager: User {$order->userName}(ID:{$order->userId}) submitted a new order {$order->id}, please handle it ASAP!" );
 79
 80             }
 81
 82         }
 83
 84     }
 85
 86     Client::test();
 87
 88
 89     <?php
 90
 91     /**
 92      *
 93      * 观察者模式 Observer
 94      *
 95      */
 96
 97     function output($string) {
 98         echo    $string . "n";
 99     }
100
101
102     //订单数据对象简单模拟,这个是实际需要被观察的对象(Subject),但是我们将其独立,然后
103     //通过构造方法传入到我们模式中的Subject中,这样使具体业务更加独立
104     class Order{
105         //订单号
106         private $id = ‘‘;
107
108         //用户ID
109         private $userId = ‘‘;
110
111         //用户名
112         private $userName = ‘‘;
113
114         //价格
115         private $price = ‘‘;
116
117         //下单时间
118         private $orderTime = ‘‘;
119
120         //订单数据填充简单模拟,实际应用中可能会读取用户表单输入并处理
121         public function __set($name, $value){
122             if (isset($this->$name)){
123                 $this->$name = $value;
124             }
125         }
126
127         //获取订单属性
128         public function __get($name){
129             if (isset($this->$name)){
130                 return $this->$name;
131             }
132             return "";
133         }
134     }
135
136     //被观察者, 负责维护观察者并在变化发生是通知观察者
137     class OrderSubject implements SplSubject {
138         private $observers;
139         private $order;
140
141         public function __construct(Order $order) {
142             $this->observers = new SplObjectStorage();
143             $this->order = $order;
144         }
145
146         //增加一个观察者
147         public function attach(SplObserver $observer) {
148             $this->observers->attach($observer);
149         }
150
151         //移除一个观察者
152         public function detach(SplObserver $observer) {
153             $this->observers->detach($observer);
154         }
155
156         //通知所有观察者
157         public function notify() {
158             foreach ($this->observers as $observer) {
159                 $observer->update($this);
160             }
161         }
162
163         //返回主体对象的具体实现,供观察者调用
164         public function getOrder() {
165             return $this->order;
166         }
167     }
168
169     //记录业务数据日志 (ActionLogObserver),实际可能还要抽象一层以处理不同的Action(业务操作),这里省略
170     class ActionLogObserver implements SplObserver{
171         public function update(SplSubject $subject) {
172              $order = $subject->getOrder();
173              //实际应用可能会写到日志文件中,这里直接输出
174              output( "[OrderId:{$order->id}] [UseId:{$order->userId}] [Price:{$order->price}]" );
175         }
176     }
177
178     //给用户发送订单确认邮件 (UserMailObserver)
179     class UserMailObserver implements SplObserver{
180         public function update(SplSubject $subject) {
181              $order = $subject->getOrder();
182              //实际应用会调用邮件发送服务如sendmail,这里直接输出
183              output( "Dear {$order->userName}: Your order {$order->id} was confirmed!" );
184         }
185     }
186
187     //给管理人员发订单处理通知邮件 (AdminMailObserver)
188     class AdminMailObserver implements SplObserver{
189         public function update(SplSubject $subject) {
190              $order = $subject->getOrder();
191              //实际应用会调用邮件发送服务如sendmail,这里直接输出
192              output( "Dear Manager: User {$order->userName}(ID:{$order->userId}) submitted a new order {$order->id}, please handle it ASAP!" );
193         }
194     }
195
196     //假设的DB类,便于测试,实际会存入真实数据库
197     class FakeDB{
198         public function save($data){
199             return true;
200         }
201     }
202
203
204     class Client {
205
206         public static function test() {
207
208             //初始化一个订单数据
209             $order = new Order();
210             $order->id = 1001;
211             $order->userId = 9527;
212             $order->userName = "God";
213             $order->price = 20.0;
214             $order->orderTime = time();
215
216             //绑定观察者
217             $subject = new OrderSubject($order);
218             $actionLogObserver = new ActionLogObserver();
219             $userMailObserver = new UserMailObserver();
220             $adminMailObserver = new AdminMailObserver();
221             $subject->attach($actionLogObserver);
222             $subject->attach($userMailObserver);
223             $subject->attach($adminMailObserver);
224             //向数据库保存订单
225             $db = new FakeDB();
226             $result = $db->save($order);
227             if ($result){
228                 //通知观察者
229                 $subject->notify();
230             }
231
232         }
233
234     }
235
236     Client::test();

5、中介者模式(Mediator):
用中介对象封装一系列的对象交互,中介使各对象不需要显式地相互引 用。
类似于邮局,邮寄者和收件者不用自己跑很远路,通过邮局就可以。
好处:简化了对象之间的关系,减少子类的生成。
弊端:中介对象可能变得非常复杂,系统难以维护。
应用场景:不需要显示地建立交互

代码实现

 1 /**
 2  *
 3  * 中介者模式 Mediator
 4  *
 5  */
 6
 7
 8 function output($string) {
 9     echo    $string . "n";
10 }
11
12
13
14
15 abstract class Mediator { // 中介者角色
16     abstract public function send($message,$colleague);
17 }
18
19 abstract class Colleague { // 抽象对象
20     private $_mediator = null;
21     public function __construct($mediator) {
22         $this->_mediator = $mediator;
23     }
24     public function send($message) {
25         $this->_mediator->send($message,$this);
26     }
27     abstract public function notify($message);
28 }
29
30 class ConcreteMediator extends Mediator { // 具体中介者角色
31     private $_colleague1 = null;
32     private $_colleague2 = null;
33     public function send($message,$colleague) {
34         if($colleague == $this->_colleague1) {
35             $this->_colleague1->notify($message);
36         } else {
37             $this->_colleague2->notify($message);
38         }
39     }
40     public function set($colleague1,$colleague2) {
41         $this->_colleague1 = $colleague1;
42         $this->_colleague2 = $colleague2;
43     }
44 }
45
46 class Colleague1 extends Colleague { // 具体对象角色
47     public function notify($message) {
48         output(sprintf(‘Colleague-1: %s‘, $message));
49     }
50 }
51
52 class Colleague2 extends Colleague { // 具体对象角色
53     public function notify($message) {
54         output(sprintf(‘Colleague-2: %s‘, $message));
55     }
56 }
57
58
59
60 class Client {
61
62     public static function test(){
63
64         // client
65         $objMediator = new ConcreteMediator();
66         $objC1 = new Colleague1($objMediator);
67         $objC2 = new Colleague2($objMediator);
68         $objMediator->set($objC1,$objC2);
69         $objC1->send("to c2 from c1");
70         $objC2->send("to c1 from c2");
71
72     }
73
74 }
75
76 Client::test();

6、状态模式(State) :
对象在不同状态下表现出不同的行为。就像女朋友一样,高兴了牵你的 手,不高兴了遛狗。在两种状态下变现出不同的行为。
好处:避免if语句实用,方便增加新状态,封装了状态转换规则。
弊端:增加系统类和对象的数量。
应用场景:用于对象的不同功能的转换。
代码实现

  1 /**
  2  * 状态模式 State
  3  *
  4  */
  5
  6 function output($string) {
  7     echo    $string . "n";
  8 }
  9
 10 abstract class ILift {
 11
 12     //电梯的四个状态
 13     const OPENING_STATE = 1;  //门敞状态
 14     const CLOSING_STATE = 2;  //门闭状态
 15     const RUNNING_STATE = 3;  //运行状态
 16     const STOPPING_STATE = 4; //停止状态;
 17
 18     //设置电梯的状态
 19     public abstract function setState($state);
 20
 21     //首先电梯门开启动作
 22     public abstract function open();
 23
 24     //电梯门有开启,那当然也就有关闭了
 25     public abstract function close();
 26
 27     //电梯要能上能下,跑起来
 28     public abstract function run();
 29
 30     //电梯还要能停下来
 31     public abstract function stop();
 32
 33 }
 34
 35 /**
 36  * 电梯的实现类
 37  */
 38 class Lift extends ILift {
 39
 40     private $state;
 41
 42     public function setState($state) {
 43         $this->state = $state;
 44     }
 45
 46     //电梯门关闭
 47     public function close() {
 48
 49         //电梯在什么状态下才能关闭
 50         switch ($this->state) {
 51             case ILift::OPENING_STATE:  //如果是则可以关门,同时修改电梯状态
 52                 $this->setState(ILift::CLOSING_STATE);
 53             break;
 54             case ILift::CLOSING_STATE:  //如果电梯就是关门状态,则什么都不做
 55                 //do nothing;
 56                 return ;
 57             break;
 58             case ILift::RUNNING_STATE: //如果是正在运行,门本来就是关闭的,也说明都不做
 59                 //do nothing;
 60                 return ;
 61             break;
 62             case ILift::STOPPING_STATE:  //如果是停止状态,本也是关闭的,什么也不做
 63                 //do nothing;
 64                 return ;
 65             break;
 66         }
 67
 68         output(‘Lift colse‘);
 69
 70     }
 71
 72     //电梯门开启
 73     public function open() {
 74         //电梯在什么状态才能开启
 75         switch($this->state){
 76             case ILift::OPENING_STATE: //如果已经在门敞状态,则什么都不做
 77                 //do nothing;
 78                 return ;
 79             break;
 80             case ILift::CLOSING_STATE: //如是电梯时关闭状态,则可以开启
 81                 $this->setState(ILift::OPENING_STATE);
 82             break;
 83             case ILift::RUNNING_STATE: //正在运行状态,则不能开门,什么都不做
 84             //do nothing;
 85                 return ;
 86             break;
 87             case ILift::STOPPING_STATE: //停止状态,淡然要开门了
 88                 $this->setState(ILift::OPENING_STATE);
 89             break;
 90         }
 91         output(‘Lift open‘);
 92     }
 93     ///电梯开始跑起来
 94     public function run() {
 95         switch($this->state){
 96             case ILift::OPENING_STATE: //如果已经在门敞状态,则不你能运行,什么都不做
 97                 //do nothing;
 98                 return ;
 99             break;
100             case ILift::CLOSING_STATE: //如是电梯时关闭状态,则可以运行
101                 $this->setState(ILift::RUNNING_STATE);
102             break;
103             case ILift::RUNNING_STATE: //正在运行状态,则什么都不做
104                 //do nothing;
105                 return ;
106             break;
107             case ILift::STOPPING_STATE: //停止状态,可以运行
108                 $this->setState(ILift::RUNNING_STATE);
109         }
110         output(‘Lift run‘);
111     }
112
113     //电梯停止
114     public function stop() {
115         switch($this->state){
116             case ILift::OPENING_STATE: //如果已经在门敞状态,那肯定要先停下来的,什么都不做
117                 //do nothing;
118                 return ;
119             break;
120             case ILift::CLOSING_STATE: //如是电梯时关闭状态,则当然可以停止了
121                 $this->setState(ILift::CLOSING_STATE);
122             break;
123             case ILift::RUNNING_STATE: //正在运行状态,有运行当然那也就有停止了
124                 $this->setState(ILift::CLOSING_STATE);
125             break;
126             case ILift::STOPPING_STATE: //停止状态,什么都不做
127                 //do nothing;
128                 return ;
129             break;
130         }
131         output(‘Lift stop‘);
132     }
133
134 }
135
136
137
138 class Client {
139
140     public static function test() {
141
142         $lift = new Lift();
143
144         //电梯的初始条件应该是停止状态
145         $lift->setState(ILift::STOPPING_STATE);
146         //首先是电梯门开启,人进去
147         $lift->open();
148
149         //然后电梯门关闭
150         $lift->close();
151
152         //再然后,电梯跑起来,向上或者向下
153         $lift->run();
154
155          //最后到达目的地,电梯挺下来
156         $lift->stop();
157
158     }
159
160 }
161
162 Client::test();
163
164
165 <?php
166
167 /**
168  *
169  * 状态模式 State
170  *
171  */
172
173 function output($string) {
174     echo    $string . "n";
175 }
176
177 /**
178  *
179  * 定义一个电梯的接口
180  */
181 abstract class LiftState{
182
183     //定义一个环境角色,也就是封装状态的变换引起的功能变化
184     protected  $_context;
185
186     public function setContext(Context $context){
187         $this->_context = $context;
188     }
189
190     //首先电梯门开启动作
191     public abstract function open();
192
193     //电梯门有开启,那当然也就有关闭了
194     public abstract function close();
195
196     //电梯要能上能下,跑起来
197     public abstract function run();
198
199     //电梯还要能停下来,停不下来那就扯淡了
200     public abstract function stop();
201
202 }
203
204
205 /**
206  * 环境类:定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。
207  */
208 class Context {
209     //定义出所有的电梯状态
210     static  $openningState = null;
211     static  $closeingState = null;
212     static  $runningState  = null;
213     static  $stoppingState = null;
214
215     public function __construct() {
216         self::$openningState = new OpenningState();
217         self::$closeingState = new ClosingState();
218         self::$runningState =  new RunningState();
219         self::$stoppingState = new StoppingState();
220
221     }
222
223     //定一个当前电梯状态
224     private  $_liftState;
225
226     public function getLiftState() {
227         return $this->_liftState;
228     }
229
230     public function setLiftState($liftState) {
231         $this->_liftState = $liftState;
232         //把当前的环境通知到各个实现类中
233         $this->_liftState->setContext($this);
234     }
235
236
237     public function open(){
238         $this->_liftState->open();
239     }
240
241     public function close(){
242         $this->_liftState->close();
243     }
244
245     public function run(){
246         $this->_liftState->run();
247     }
248
249     public function stop(){
250         $this->_liftState->stop();
251     }
252 }
253
254 /**
255  * 在电梯门开启的状态下能做什么事情
256  */
257 class OpenningState extends LiftState {
258
259     /**
260      * 开启当然可以关闭了,我就想测试一下电梯门开关功能
261      *
262      */
263     public function close() {
264         //状态修改
265         $this->_context->setLiftState(Context::$closeingState);
266         //动作委托为CloseState来执行
267         $this->_context->getLiftState()->close();
268     }
269
270     //打开电梯门
271     public function open() {
272         output(‘lift open...‘);
273     }
274     //门开着电梯就想跑,这电梯,吓死你!
275     public function run() {
276         //do nothing;
277     }
278
279     //开门还不停止?
280     public function stop() {
281         //do nothing;
282     }
283
284 }
285
286 /**
287  * 电梯门关闭以后,电梯可以做哪些事情
288  */
289 class ClosingState extends LiftState {
290
291     //电梯门关闭,这是关闭状态要实现的动作
292     public function close() {
293         output(‘lift close...‘);
294
295     }
296     //电梯门关了再打开,逗你玩呢,那这个允许呀
297     public function open() {
298         $this->_context->setLiftState(Context::$openningState);  //置为门敞状态
299         $this->_context->getLiftState()->open();
300     }
301
302     //电梯门关了就跑,这是再正常不过了
303     public function run() {
304         $this->_context->setLiftState(Context::$runningState); //设置为运行状态;
305         $this->_context->getLiftState()->run();
306     }
307
308     //电梯门关着,我就不按楼层
309
310     public function stop() {
311         $this->_context->setLiftState(Context::$stoppingState);  //设置为停止状态;
312         $this->_context->getLiftState()->stop();
313     }
314
315 }
316
317 /**
318  * 电梯在运行状态下能做哪些动作
319  */
320 class RunningState extends LiftState {
321
322     //电梯门关闭?这是肯定了
323     public function close() {
324         //do nothing
325     }
326
327     //运行的时候开电梯门?你疯了!电梯不会给你开的
328     public function open() {
329         //do nothing
330     }
331
332     //这是在运行状态下要实现的方法
333     public function run() {
334         output(‘lift run...‘);
335     }
336
337     //这个事绝对是合理的,光运行不停止还有谁敢做这个电梯?!估计只有上帝了
338     public function stop() {
339         $this->_context->setLiftState(Context::$stoppingState); //环境设置为停止状态;
340         $this->_context->getLiftState()->stop();
341     }
342
343 }
344
345
346
347 /**
348  * 在停止状态下能做什么事情
349  */
350 class StoppingState extends LiftState {
351
352     //停止状态关门?电梯门本来就是关着的!
353     public function close() {
354         //do nothing;
355     }
356
357     //停止状态,开门,那是要的!
358     public function open() {
359         $this->_context->setLiftState(Context::$openningState);
360         $this->_context->getLiftState()->open();
361     }
362     //停止状态再跑起来,正常的很
363     public function run() {
364         $this->_context->setLiftState(Context::$runningState);
365         $this->_context->getLiftState()->run();
366     }
367     //停止状态是怎么发生的呢?当然是停止方法执行了
368     public function stop() {
369         output(‘lift stop...‘);
370     }
371
372 }
373
374 /**
375  * 模拟电梯的动作
376  */
377 class Client {
378
379     public static function test() {
380         $context = new Context();
381         $context->setLiftState(new ClosingState());
382
383         $context->open();
384         $context->close();
385         $context->run();
386         $context->stop();
387     }
388 }
389
390 Client::test();

7、职责链模式 (Chainof Responsibility):
多个对象有机会处理请求,为请求发送者和接收者解耦。就像银行里 的取款机,不管那一台都可以取到钱。
好处:简单化对象隐藏链结构,便于添加新职责节点。
弊端:请求可能没有接受者,或者被多个接收者调用,性能降低。
应用场景:处理多种请求。

代码实现

  1 /**
  2  * 职责链模式 Chain of Responsibility
  3  *
  4  */
  5
  6 function output($string) {
  7     echo    $string . "n";
  8 }
  9
 10 /**
 11  * 加入在公司里,如果你的请假时间小于0.5天,那么只需要向leader打声招呼就OK了。
 12   如果0.5<=请假天数<=3天,需要先leader打声招呼,然后部门经理签字。
 13   如果3<请假天数,需要先leader打声招呼,然后到部门经理签字,最后总经经理确认签字,
 14     如果请假天数超过10天,是任何人都不能批准的。
 15  */
 16
 17
 18 /**
 19  * 抽象处理者角色(Handler:Approver):定义一个处理请求的接口,和一个后继连接(可选)
 20  *
 21  */
 22 abstract class Handler
 23 {
 24
 25     protected $_handler = null;
 26     protected $_handlerName = null;
 27
 28     public function setSuccessor($handler)
 29     {
 30         $this->_handler = $handler;
 31     }
 32
 33     protected  function _success($request)
 34     {
 35         output(sprintf("%s‘s request was passed", $request->getName()));
 36         return true;
 37     }
 38     abstract function handleRequest($request);
 39 }
 40
 41 /**
 42  * 具体处理者角色(ConcreteHandler:President):处理它所负责的请求,可以访问后继者,如果可以处理请求则处理,否则将该请求转给他的后继者。
 43  *
 44  */
 45 class ConcreteHandlerLeader extends Handler
 46 {
 47     function __construct($handlerName){
 48         $this->_handlerName = $handlerName;
 49     }
 50     public function handleRequest($request)
 51     {
 52         if($request->getDay() < 0.5) {
 53             output(sprintf(‘%s was told‘, $this->_handlerName));       // 已经跟leader招呼了
 54             return $this->_success($request);
 55         }
 56         if ($this->_handler instanceof Handler) {
 57             return $this->_handler->handleRequest($request);
 58         }
 59     }
 60 }
 61 /**
 62  * Manager
 63  *
 64  */
 65 class ConcreteHandlerManager extends Handler
 66 {
 67     function __construct($handlerName){
 68         $this->_handlerName = $handlerName;
 69     }
 70
 71     public function handleRequest($request)
 72     {
 73         if(0.5 <= $request->getDay() && $request->getDay()<=3) {
 74             output(sprintf(‘%s signed‘, $this->_handlerName));       // 部门经理签字
 75             return $this->_success($request);
 76         }
 77         if ($this->_handler instanceof Handler) {
 78             return $this->_handler->handleRequest($request);
 79         }
 80     }
 81
 82 }
 83
 84 class ConcreteHandlerGeneralManager extends Handler
 85 {
 86     function __construct($handlerName){
 87         $this->_handlerName = $handlerName;
 88     }
 89
 90     public function handleRequest($request)
 91     {
 92         if(3 < $request->getDay() && $request->getDay() < 10){
 93             output(sprintf(‘%s signed‘, $this->_handlerName));       // 总经理签字
 94             return $this->_success($request);
 95         }
 96         if ($this->_handler instanceof Handler) {
 97             return $this->_handler->handleRequest($request);
 98         } else {
 99             output(sprintf(‘no one can approve request more than 10 days‘));
100         }
101     }
102
103 }
104
105 /**
106  * 请假申请
107  *
108  */
109 class Request
110 {
111     private $_name;
112     private $_day;
113     private $_reason;
114
115     function __construct($name= ‘‘, $day= 0, $reason = ‘‘){
116         $this->_name = $name;
117         $this->_day = $day;
118         $this->_reason = $reason;
119     }
120
121     public function setName($name){
122         $this->_name = $name;
123     }
124
125     public function getName(){
126         return  $this->_name;
127     }
128
129     public function setDay($day){
130         $this->_day = $day;
131     }
132
133     public function getDay(){
134         return  $this->_day ;
135     }
136
137     public function setReason($reason ){
138          $this->_reason = $reason;
139     }
140
141     public function getReason( ){
142         return  $this->_reason;
143     }
144 }
145
146
147 class Client {
148
149     public static function test(){
150
151         $leader = new ConcreteHandlerLeader(‘leader‘);
152         $manager = new ConcreteHandlerManager(‘manager‘);
153         $generalManager = new ConcreteHandlerGeneralManager(‘generalManager‘);
154
155         //请求实例
156         $request = new Request(‘ucai‘,4,‘休息‘);
157
158         $leader->setSuccessor($manager);
159         $manager->setSuccessor($generalManager);
160         $result =  $leader->handleRequest($request);
161     }
162
163 }
164
165 Client::test();

8、策略模式(Strategy):
定义一系列算法,把每一个算法封装起来,并且使它们可相互替换。 就像篮球队里的球员,场上的和场下休息的。教练可以让场上的下来,也 可以让场下的上阵。
好处:定义可重用的一系列算法和行为,并且消除了if else语句。
弊端:调用端必须知道所有策略类。
应用场景:用于对象间的替换。

代码实现

 1 /**
 2  * 策略模式 Strategy
 3  *
 4  */
 5
 6
 7 function output($string) {
 8     echo    $string . "n";
 9 }
10
11 //策略基类接口
12
13 interface IStrategy {
14     public function OnTheWay();
15 }
16
17 class WalkStrategy implements IStrategy {
18     public function OnTheWay() {
19         output( ‘在路上步行‘);
20     }
21 }
22
23 class RideBickStrategy implements IStrategy {
24     public function OnTheWay() {
25         output( ‘在路上骑自行车‘);
26     }
27 }
28
29 class CarStrategy implements IStrategy {
30     public function OnTheWay() {
31         output( ‘在路上开车‘);
32     }
33 }
34
35 //选择策略类Context
36 class Context {
37     public function find($strategy) {
38         $strategy->OnTheWay();
39     }
40 }
41
42 class Client {
43
44     public static function test(){
45
46         $travel = new Context();
47         $travel->find(new WalkStrategy());
48         $travel->find(new RideBickStrategy());
49         $travel->find(new CarStrategy());
50
51     }
52
53 }
54
55 Client::test();

已知模式
1、备忘录模式(Memento):
保存对象在一时刻的状态。亲,还记得“老师来了记得叫我一下”的 同桌的他吗?
好处:给用户提供了一种可以恢复状态的机制。
弊端:消耗资源。
应用场景:用于需要保存的数据。

代码实现

  1 /**
  2  *
  3  * 备忘录模式 Memento
  4  *
  5  */
  6
  7 function output($string) {
  8     echo    $string . "n";
  9 }
 10
 11
 12 class Originator { // 发起人(Originator)角色
 13     private $_state;
 14     public function __construct() {
 15         $this->_state = ‘‘;
 16     }
 17     public function createMemento() { // 创建备忘录
 18         return new Memento($this->_state);
 19     }
 20     public function restoreMemento(Memento $memento) { // 将发起人恢复到备忘录对象记录的状态上
 21         $this->_state = $memento->getState();
 22     }
 23     public function setState($state) { $this->_state = $state; }
 24     public function getState() { return $this->_state; }
 25     public function showState() {
 26         output($this->_state);
 27     }
 28
 29 }
 30
 31 class Memento { // 备忘录(Memento)角色
 32     private $_state;
 33     public function __construct($state) {
 34         $this->setState($state);
 35     }
 36     public function getState() { return $this->_state; }
 37     public function setState($state) { $this->_state = $state;}
 38 }
 39
 40 class Caretaker { // 负责人(Caretaker)角色
 41     private $_memento;
 42     public function getMemento() { return $this->_memento; }
 43     public function setMemento(Memento $memento) { $this->_memento = $memento; }
 44 }
 45
 46 class Client {
 47
 48     public static function test(){
 49
 50         $org = new Originator();
 51         $org->setState(‘open‘);
 52         $org->showState();
 53
 54         /* 创建备忘 */
 55         $memento = $org->createMemento();
 56
 57         /* 通过Caretaker保存此备忘 */
 58         $caretaker = new Caretaker();
 59         $caretaker->setMemento($memento);
 60
 61         /* 改变目标对象的状态 */
 62         $org->setState(‘close‘);
 63         $org->showState();
 64
 65         /* 还原操作 */
 66         $org->restoreMemento($caretaker->getMemento());
 67         $org->showState();
 68
 69     }
 70
 71 }
 72
 73 Client::test();
 74
 75
 76 return;
 77
 78
 79 try {
 80
 81     $db->beginTransaction();
 82
 83     $succ   = $db->exec($sql_1);
 84     if (!$succ) {
 85         throw new Exception(‘SQL 1 update failed‘);
 86     }
 87
 88     $succ   = $db->exec($sql_2);
 89     if (!$succ) {
 90         throw new Exception(‘SQL 2 update failed‘);
 91     }
 92
 93     $succ   = $db->exec($sql_3);
 94     if (!$succ) {
 95         throw new Exception(‘SQL 3 update failed‘);
 96     }
 97
 98     $db->commit();
 99
100 } catch (Exception $exp) {
101
102     $db->rollBack();
103
104 }

深度模式
1、解释器模式(Interpreter):
定义语言的文法,并建立一个解释器解释该语言中的句子。每个用过 字典的童鞋都懂滴。
好处:可扩展性比较好,灵活性大
弊端:可能难以维护复杂的文法
应用场景:用于成对或者一对多的需求中

2、访问者模式(Visitor):
封装某些用于作用于某种数据结构中各元素的操作,可以在不改变数 据结构的前提下定义作用于这些元素的新操作。如银行排号机。
好处:将相关的事物集中到一个访问者对象中。
弊端:增加新数据结构很困难。
应用场景:排队,排号。

三、总结
本篇介绍了行为型模式,行为模式涉及到算法和对象职责间的分配,行为类模式采用继承机制在类间分派行为,TemplateMethod和Interpreter是类行为
模式。行为对象模式使用对象复合而不是继承,一些行为对象模式描述了一组相互对等的对象如何相互协作以完成其中任何一个对象都单独无法完成的任务,如
Mediator在对象间引入一个mediator对象提供了松耦合所需的间接性;
Chain of Responsibility提供了更松的耦合,它通过一条候选对象链隐式的向一个对象发松请求,可以运行时刻决定哪些候选者参与到链中;
Observer定义并保持了对象间的依赖关系;其它的行为对象模式常将行为封装封装在一个对象中,并将请求指派给它,
Strategy模式将算法封装在对象中,这样可以方面的改变和指定一个对象所使用的算法;
Command模式将请求封装在对象中,这样它就可以作为参数来传递,已可以存储在历史列表中或以其它方式使用;
State模式封装一个对象的状态,使得当这个对象的状态对象变化时,该对象可改变它的行为;
Visitor模式封装分布于多个类之间的行为;而Iterator模式则抽象了访问和遍历一个集合中对象的方式。

原文地址:https://www.cnblogs.com/hb01846/p/10946488.html

时间: 2024-11-01 16:26:00

php设计模式(四):行为型模式的相关文章

设计模式之创建型模式(上)

没有总结的学习不算学习,这一个月的学习可谓收获多多啊,接下来与大家分享一下. 一.设计模式的分类 总体来说设计模式分为三大类: 1.创建型模式,共五种. 2.结构型模式,共七种. 3.行为型模式,共十一种. 首先研究创建型模式 二. 概述 创建型模式,就是用来创建对象的模式,抽象了实例化的过程.它帮助一个系统独 立于如何创建.组合和表示它的那些对象. 三. 为什么需要创建型模式 所有的创建型模式都有两个永恒的主旋律: 第一,它们都将系统使用哪些具体类的信息封装起来: 第二,它们隐藏了这些类的实例

Java经典23种设计模式之行为型模式(三)

本文接着介绍11种行为型模式里的备忘录模式.观察者模式.状态模式. 一.备忘录模式 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可以将该对象恢复到原先保存的状态.还是比较好理解的. 1.Memento 备忘录存储原发器对象的内部状态,这个类就是要存储的对象的状态.状态需要多少个变量,在Memento里就写多少个变量. public class Memento { private String state; public Meme*to(String st

设计模式 (创建型模式)

  设计模式 创建型模式 1.创建型模式         创建型模式,包括了5种设计模式,分别是 Singleton (单例模式),Factory(工厂模式),AbstractFactory(抽象工厂模式),Builder(创建者),Prototype(原型) ,创建型模式主要作用就是抽象了实例化过程.他们帮助一个系统独立于如何创建.组合和表示他的那些对象.一个类创建型模式使用继承改变被实例化的类.而一个对象创建型模式将实例化委托给另一个对象. 2.Singleton (单例模式)      单

Java经典23种设计模式之行为型模式(一)

行为型设计模式有11种,分别是Chain of Responsibility ( 责任链模式 ).Command ( 命令模式 ).Interpreter ( 解释器模式 ) .Iterator ( 迭代器模式 ).Mediator ( 中介者模式 ) .Memento ( 备忘录模式 ) .Observer ( 观察者模式 ).State ( 状态模式 ) .Strategy ( 策略模式 ).TemplateMethod ( 模板方法 ).Visitor ( 访问者模式 ),本文介绍这11种

设计模式(33)-----行为型模式-----访问者设计模式

访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法.通过这种方式,元素的执行算法可以随着访问者改变而改变.这种类型的设计模式属于行为型模式.根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作. 介绍 意图:主要将数据结构与数据操作分离. 主要解决:稳定的数据结构和易变的操作耦合问题. 何时使用:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封

设计模式系列 - 创建型模式

单例模式 懒汉式,线程不安全. 除非是单线程程序,否则不推荐使用. public class Singleton { private static Singleton instance; private Singleton (){} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 饿汉式,线程安全 当程序总是使用这个

Java经典23种设计模式之行为型模式(四)

本文介绍11种行为型设计模式里的策略模式.模板方法.访问者模式. 一.策略模式 定义一系列的算法,把它们每个封装起来,并且使它们可相互替换.本模式使得算法可独立于使用它的客户而变化. 1.Strategy定义所有支持的算法的公共接口.Context使用这个接口来调用某ConcreteStrategy定义的算法. public abstract class Strategy {    public abstract void method();} 2.ConcreteStrategy以Strate

设计模式之行为型模式(四)

行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配. 行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为.由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性. 行为型模式是 GoF 设计模式中最为庞大的一类,它包含以下 11 种模式. 模板方法(Template Method)模式:定义

设计模式之创建型模式

一.前言 设计模式应该是在软件工程的背景下进行讨论的,而不是为了设计模式而论设计模式.设计模式是软件工程面向对象设计工作中一个抽象.归纳.总结的过程.软件设计的最高目标和最高准则就是易扩展,易复用,易维护, 灵活性高,高可用,稳定性高一切的设计原则和设计模式最终的目标都是向这个目标靠拢的. 二.面向对象设计六大原则 任何的设计模式都是基于面向对象的特性(抽象.封装.继承.多态)和设计原则进行设计和实现的,是面向对象设计原则的在不同场景下的实现方案. 抽象:抽离变化的部分,引入抽象层,实现具体实现

设计模式3—行为型模式

行为型模式用来对类或对象怎样交互和怎样分配职责进行描述,主要包含以下11种设计模式: 1. 模板方法模式(Template Method Pattern)使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 2. 命令模式(Command Pattern)是将一个请求封装为一个对象,从而使你可用不同的请求对客户端进行参数化:对请求排队或记录请求日志,以及支持可撤销的操作. 3. 责任链模式(Chain of Responsibility Pattern),在该模式里,很多对象由每一个