原文详见:http://www.ucai.cn/blogdetail/7023?mid=1&f=5
可以在线运行查看效果哦!
《接上文》
5、中介者模式(Mediator) :
用中介对象封装一系列的对象交互,中介使各对象不需要显式地相互引用。类似于邮局,邮寄者和收件者不用自己跑很远路,通过邮局就可以。
好处:简化了对象之间的关系,减少子类的生成。
弊端:中介对象可能变得非常复杂,系统难以维护。
应用场景:不需要显示地建立交互。
代码实现:
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 |
<?php /** * 优才网公开课示例代码 * * 中介者模式 Mediator * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function
output( $string ) { echo
$string . "\n" ; } abstract
class Mediator { // 中介者角色 abstract
public function send( $message , $colleague ); } abstract
class Colleague { // 抽象对象 private
$_mediator = null; public
function __construct( $mediator ) { $this ->_mediator = $mediator ; } public
function send( $message ) { $this ->_mediator->send( $message , $this ); } abstract
public function notify( $message ); } class ConcreteMediator extends
Mediator { // 具体中介者角色 private
$_colleague1 = null; private
$_colleague2 = null; public
function send( $message , $colleague ) { if ( $colleague
== $this ->_colleague1) { $this ->_colleague1->notify( $message ); } else
{ $this ->_colleague2->notify( $message ); } } public
function set( $colleague1 , $colleague2 ) { $this ->_colleague1 = $colleague1 ; $this ->_colleague2 = $colleague2 ; } } class Colleague1 extends
Colleague { // 具体对象角色 public
function notify( $message ) { output(sprintf( ‘Colleague-1: %s‘ , $message )); } } class Colleague2 extends
Colleague { // 具体对象角色 public
function notify( $message ) { output(sprintf( ‘Colleague-2: %s‘ , $message )); } } class Client { public
static function test(){ // client $objMediator
= new ConcreteMediator(); $objC1
= new Colleague1( $objMediator ); $objC2
= new Colleague2( $objMediator ); $objMediator ->set( $objC1 , $objC2 ); $objC1 ->send( "to c2 from c1" ); $objC2 ->send( "to c1 from c2" ); } } Client::test(); |
6、状态模式(State) :
对象在不同状态下表现出不同的行为。就像女朋友一样,高兴了牵你的手,不高兴了遛狗。在两种状态下变现出不同的行为。
好处:避免if语句实用,方便增加新状态,封装了状态转换规则。
弊端:增加系统类和对象的数量。
应用场景:用于对象的不同功能的转换。
代码实现:
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168 |
<?php /** * 优才网公开课示例代码 * * 状态模式 State * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function
output( $string ) { echo
$string . "\n" ; } abstract
class ILift { //电梯的四个状态 const
OPENING_STATE = 1; //门敞状态 const
CLOSING_STATE = 2; //门闭状态 const
RUNNING_STATE = 3; //运行状态 const
STOPPING_STATE = 4; //停止状态; //设置电梯的状态 public
abstract function setState( $state ); //首先电梯门开启动作 public
abstract function open(); //电梯门有开启,那当然也就有关闭了 public
abstract function close(); //电梯要能上能下,跑起来 public
abstract function run(); //电梯还要能停下来 public
abstract function stop(); } /** * 电梯的实现类 */ class Lift extends
ILift { private
$state ; public
function setState( $state ) { $this ->state = $state ; } //电梯门关闭 public
function close() { //电梯在什么状态下才能关闭 switch
( $this ->state) { case
ILift::OPENING_STATE: //如果是则可以关门,同时修改电梯状态 $this ->setState(ILift::CLOSING_STATE); break ; case
ILift::CLOSING_STATE: //如果电梯就是关门状态,则什么都不做 //do nothing; return
; break ; case
ILift::RUNNING_STATE: //如果是正在运行,门本来就是关闭的,也说明都不做 //do nothing; return
; break ; case
ILift::STOPPING_STATE: //如果是停止状态,本也是关闭的,什么也不做 //do nothing; return
; break ; } output( ‘Lift colse‘ ); } //电梯门开启 public
function open() { //电梯在什么状态才能开启 switch ( $this ->state){ case
ILift::OPENING_STATE: //如果已经在门敞状态,则什么都不做 //do nothing; return
; break ; case
ILift::CLOSING_STATE: //如是电梯时关闭状态,则可以开启 $this ->setState(ILift::OPENING_STATE); break ; case
ILift::RUNNING_STATE: //正在运行状态,则不能开门,什么都不做 //do nothing; return
; break ; case
ILift::STOPPING_STATE: //停止状态,淡然要开门了 $this ->setState(ILift::OPENING_STATE); break ; } output( ‘Lift open‘ ); } ///电梯开始跑起来 public
function run() { switch ( $this ->state){ case
ILift::OPENING_STATE: //如果已经在门敞状态,则不你能运行,什么都不做 //do nothing; return
; break ; case
ILift::CLOSING_STATE: //如是电梯时关闭状态,则可以运行 $this ->setState(ILift::RUNNING_STATE); break ; case
ILift::RUNNING_STATE: //正在运行状态,则什么都不做 //do nothing; return
; break ; case
ILift::STOPPING_STATE: //停止状态,可以运行 $this ->setState(ILift::RUNNING_STATE); } output( ‘Lift run‘ ); } //电梯停止 public
function stop() { switch ( $this ->state){ case
ILift::OPENING_STATE: //如果已经在门敞状态,那肯定要先停下来的,什么都不做 //do nothing; return
; break ; case
ILift::CLOSING_STATE: //如是电梯时关闭状态,则当然可以停止了 $this ->setState(ILift::CLOSING_STATE); break ; case
ILift::RUNNING_STATE: //正在运行状态,有运行当然那也就有停止了 $this ->setState(ILift::CLOSING_STATE); break ; case
ILift::STOPPING_STATE: //停止状态,什么都不做 //do nothing; return
; break ; } output( ‘Lift stop‘ ); } } class
Client { public
static function test() { $lift
= new Lift(); //电梯的初始条件应该是停止状态 $lift ->setState(ILift::STOPPING_STATE); //首先是电梯门开启,人进去 $lift ->open(); //然后电梯门关闭 $lift ->close(); //再然后,电梯跑起来,向上或者向下 $lift ->run(); //最后到达目的地,电梯挺下来 $lift ->stop(); } } Client::test(); |
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229 |
<?php /** * 优才网公开课示例代码 * * 状态模式 State * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function
output( $string ) { echo
$string . "\n" ; } /** * * 定义一个电梯的接口 */ abstract
class LiftState{ //定义一个环境角色,也就是封装状态的变换引起的功能变化 protected
$_context ; public
function setContext(Context $context ){ $this ->_context = $context ; } //首先电梯门开启动作 public
abstract function open(); //电梯门有开启,那当然也就有关闭了 public
abstract function close(); //电梯要能上能下,跑起来 public
abstract function run(); //电梯还要能停下来,停不下来那就扯淡了 public
abstract function stop(); } /** * 环境类:定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。 */ class Context { //定义出所有的电梯状态 static
$openningState = null; static
$closeingState = null; static
$runningState = null; static
$stoppingState = null; public
function __construct() { self:: $openningState
= new OpenningState(); self:: $closeingState
= new ClosingState(); self:: $runningState
= new
RunningState(); self:: $stoppingState
= new StoppingState(); } //定一个当前电梯状态 private
$_liftState ; public
function getLiftState() { return
$this ->_liftState; } public
function setLiftState( $liftState ) { $this ->_liftState = $liftState ; //把当前的环境通知到各个实现类中 $this ->_liftState->setContext( $this ); } public
function open(){ $this ->_liftState->open(); } public
function close(){ $this ->_liftState->close(); } public
function run(){ $this ->_liftState->run(); } public
function stop(){ $this ->_liftState->stop(); } } /** * 在电梯门开启的状态下能做什么事情 */ class OpenningState extends
LiftState { /** * 开启当然可以关闭了,我就想测试一下电梯门开关功能 * */ public
function close() { //状态修改 $this ->_context->setLiftState(Context:: $closeingState ); //动作委托为CloseState来执行 $this ->_context->getLiftState()->close(); } //打开电梯门 public
function open() { output( ‘lift open...‘ ); } //门开着电梯就想跑,这电梯,吓死你! public
function run() { //do nothing; } //开门还不停止? public
function stop() { //do nothing; } } /** * 电梯门关闭以后,电梯可以做哪些事情 */ class
ClosingState extends
LiftState { //电梯门关闭,这是关闭状态要实现的动作 public
function close() { output( ‘lift close...‘ ); } //电梯门关了再打开,逗你玩呢,那这个允许呀 public
function open() { $this ->_context->setLiftState(Context:: $openningState ); //置为门敞状态 $this ->_context->getLiftState()->open(); } //电梯门关了就跑,这是再正常不过了 public
function run() { $this ->_context->setLiftState(Context:: $runningState ); //设置为运行状态; $this ->_context->getLiftState()->run(); } //电梯门关着,我就不按楼层 public
function stop() { $this ->_context->setLiftState(Context:: $stoppingState ); //设置为停止状态; $this ->_context->getLiftState()->stop(); } } /** * 电梯在运行状态下能做哪些动作 */ class
RunningState extends
LiftState { //电梯门关闭?这是肯定了 public
function close() { //do nothing } //运行的时候开电梯门?你疯了!电梯不会给你开的 public
function open() { //do nothing } //这是在运行状态下要实现的方法 public
function run() { output( ‘lift run...‘ ); } //这个事绝对是合理的,光运行不停止还有谁敢做这个电梯?!估计只有上帝了 public
function stop() { $this ->_context->setLiftState(Context:: $stoppingState ); //环境设置为停止状态; $this ->_context->getLiftState()->stop(); } } /** * 在停止状态下能做什么事情 */ class
StoppingState extends
LiftState { //停止状态关门?电梯门本来就是关着的! public
function close() { //do nothing; } //停止状态,开门,那是要的! public
function open() { $this ->_context->setLiftState(Context:: $openningState ); $this ->_context->getLiftState()->open(); } //停止状态再跑起来,正常的很 public
function run() { $this ->_context->setLiftState(Context:: $runningState ); $this ->_context->getLiftState()->run(); } //停止状态是怎么发生的呢?当然是停止方法执行了 public
function stop() { output( ‘lift stop...‘ ); } } /** * 模拟电梯的动作 */ class
Client { public
static function test() { $context
= new Context(); $context ->setLiftState( new
ClosingState()); $context ->open(); $context ->close(); $context ->run(); $context ->stop(); } } Client::test(); |
7、职责链模式 (Chain of Responsibility):
多个对象有机会处理请求,为请求发送者和接收者解耦。就像银行里的取款机,不管那一台都可以取到钱。
好处:简单化对象隐藏链结构,便于添加新职责节点。
弊端:请求可能没有接受者,或者被多个接收者调用,性能降低。
应用场景:处理多种请求。
代码实现:
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 |
<?php /** * 优才网公开课示例代码 * * 职责链模式 Chain of Responsibility * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function
output( $string ) { echo
$string . "\n" ; } /** * 加入在公司里,如果你的请假时间小于0.5天,那么只需要向leader打声招呼就OK了。 如果0.5<=请假天数<=3天,需要先leader打声招呼,然后部门经理签字。 如果3<请假天数,需要先leader打声招呼,然后到部门经理签字,最后总经经理确认签字, 如果请假天数超过10天,是任何人都不能批准的。 */ /** * 抽象处理者角色(Handler:Approver):定义一个处理请求的接口,和一个后继连接(可选) * */ abstract
class Handler { protected
$_handler = null; protected
$_handlerName = null; public
function setSuccessor( $handler ) { $this ->_handler = $handler ; } protected
function _success( $request ) { output(sprintf( "%s‘s request was passed" , $request ->getName())); return
true; } abstract
function handleRequest( $request ); } /** * 具体处理者角色(ConcreteHandler:President):处理它所负责的请求,可以访问后继者,如果可以处理请求则处理,否则将该请求转给他的后继者。 * */ class ConcreteHandlerLeader extends
Handler { function
__construct( $handlerName ){ $this ->_handlerName = $handlerName ; } public
function handleRequest( $request ) { if ( $request ->getDay() < 0.5) { output(sprintf( ‘%s was told‘ , $this ->_handlerName)); // 已经跟leader招呼了 return
$this ->_success( $request ); } if
( $this ->_handler instanceof
Handler) { return
$this ->_handler->handleRequest( $request ); } } } /** * Manager * */ class ConcreteHandlerManager extends
Handler { function
__construct( $handlerName ){ $this ->_handlerName = $handlerName ; } public
function handleRequest( $request ) { if (0.5 <= $request ->getDay() && $request ->getDay()<=3) { output(sprintf( ‘%s signed‘ , $this ->_handlerName)); // 部门经理签字 return
$this ->_success( $request ); } if
( $this ->_handler instanceof
Handler) { return
$this ->_handler->handleRequest( $request ); } } } class ConcreteHandlerGeneralManager extends
Handler { function
__construct( $handlerName ){ $this ->_handlerName = $handlerName ; } public
function handleRequest( $request ) { if (3 < $request ->getDay() && $request ->getDay() < 10){ output(sprintf( ‘%s signed‘ , $this ->_handlerName)); // 总经理签字 return
$this ->_success( $request ); } if
( $this ->_handler instanceof
Handler) { return
$this ->_handler->handleRequest( $request ); } else
{ output(sprintf( ‘no one can approve request more than 10 days‘ )); } } } /** * 请假申请 * */ class
Request { private
$_name ; private
$_day ; private
$_reason ; function
__construct( $name = ‘‘ , $day = 0, $reason
= ‘‘ ){ $this ->_name = $name ; $this ->_day = $day ; $this ->_reason = $reason ; } public
function setName( $name ){ $this ->_name = $name ; } public
function getName(){ return
$this ->_name; } public
function setDay( $day ){ $this ->_day = $day ; } public
function getDay(){ return
$this ->_day ; } public
function setReason( $reason
){ $this ->_reason = $reason ; } public
function getReason( ){ return
$this ->_reason; } } class
Client { public
static function test(){ $leader
= new ConcreteHandlerLeader( ‘leader‘ ); $manager
= new ConcreteHandlerManager( ‘manager‘ ); $generalManager
= new ConcreteHandlerGeneralManager( ‘generalManager‘ ); //请求实例 $request
= new Request( ‘ucai‘ ,4, ‘休息‘ ); $leader ->setSuccessor( $manager ); $manager ->setSuccessor( $generalManager ); $result
= $leader ->handleRequest( $request ); } } Client::test(); |
8、策略模式(Strategy) :
定义一系列算法,把每一个算法封装起来,并且使它们可相互替换。就像篮球队里的球员,场上的和场下休息的。教练可以让场上的下来,也可以让场下的上阵。
好处:定义可重用的一系列算法和行为,并且消除了if else语句。
弊端:调用端必须知道所有策略类。
应用场景:用于对象间的替换。
代码实现:
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
58
59
60
61 |
<?php /** * 优才网公开课示例代码 * * 策略模式 Strategy * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function
output( $string ) { echo
$string . "\n" ; } //策略基类接口 interface
IStrategy { public
function OnTheWay(); } class WalkStrategy implements
IStrategy { public
function OnTheWay() { output( ‘在路上步行‘ ); } } class RideBickStrategy implements
IStrategy { public
function OnTheWay() { output( ‘在路上骑自行车‘ ); } } class CarStrategy implements
IStrategy { public
function OnTheWay() { output( ‘在路上开车‘ ); } } //选择策略类Context class Context { public
function find( $strategy ) { $strategy ->OnTheWay(); } } class Client { public
static function test(){ $travel
= new Context(); $travel ->find( new
WalkStrategy()); $travel ->find( new
RideBickStrategy()); $travel ->find( new
CarStrategy()); } } Client::test(); |
1、备忘录模式(Memento):
保存对象在一时刻的状态。亲,还记得“老师来了记得叫我一下”的同桌的他吗?
好处:给用户提供了一种可以恢复状态的机制。
弊端:消耗资源。
应用场景:用于需要保存的数据
代码实现:
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 |
<?php /** * 优才网公开课示例代码 * * 备忘录模式 Memento * * @author 优才网全栈工程师教研组 * @see http://www.ucai.cn */ function
output( $string ) { echo
$string . "\n" ; } class Originator { // 发起人(Originator)角色 private
$_state ; public
function __construct() { $this ->_state = ‘‘ ; } public
function createMemento() { // 创建备忘录 return
new Memento( $this ->_state); } public
function restoreMemento(Memento $memento ) { // 将发起人恢复到备忘录对象记录的状态上 $this ->_state = $memento ->getState(); } public
function setState( $state ) { $this ->_state = $state ; } public
function getState() { return
$this ->_state; } public
function showState() { output( $this ->_state); } } class Memento { // 备忘录(Memento)角色 private
$_state ; public
function __construct( $state ) { $this ->setState( $state ); } public
function getState() { return
$this ->_state; } public
function setState( $state ) { $this ->_state = $state ;} } class Caretaker { // 负责人(Caretaker)角色 private
$_memento ; public
function getMemento() { return
$this ->_memento; } public
function setMemento(Memento $memento ) { $this ->_memento = $memento ; } } class Client { public
static function test(){ $org
= new Originator(); $org ->setState( ‘open‘ ); $org ->showState(); /* 创建备忘 */ $memento
= $org ->createMemento(); /* 通过Caretaker保存此备忘 */ $caretaker
= new Caretaker(); $caretaker ->setMemento( $memento ); /* 改变目标对象的状态 */ $org ->setState( ‘close‘ ); $org ->showState(); /* 还原操作 */ $org ->restoreMemento( $caretaker ->getMemento()); $org ->showState(); } } Client::test(); return ; try { $db ->beginTransaction(); $succ
= $db -> exec ( $sql_1 ); if
(! $succ ) { throw
new Exception( ‘SQL 1 update failed‘ ); } $succ
= $db -> exec ( $sql_2 ); if
(! $succ ) { throw
new Exception( ‘SQL 2 update failed‘ ); } $succ
= $db -> exec ( $sql_3 ); if
(! $succ ) { throw
new Exception( ‘SQL 3 update failed‘ ); } $db ->commit(); } catch
(Exception $exp ) { $db ->rollBack(); } |
1、解释器模式(Interpreter):
定义语言的文法,并建立一个解释器解释该语言中的句子。每个用过字典的童鞋都懂滴。
好处:可扩展性比较好,灵活性大。
弊端:可能难以维护复杂的文法。
应用场景:用于成对或者一对多的需求中。
2、访问者模式(Visitor):
封装某些用于作用于某种数据结构中各元素的操作,可以在不改变数据结构的前提下定义作用于这些元素的新操作。如银行排号机。
好处:将相关的事物集中到一个访问者对象中。
弊端:增加新数据结构很困难。
应用场景:排队,排号。
三、总结
本篇介绍了行为型模式,行为模式涉及到算法和对象职责间的分配,行为类模式采用继承机制在类间分派行为,Template Method和Interpreter是类行为模式。行为对象模式使用对象复合而不是继承,一些行为
对象模式描述了一组相互对等的对象如何相互协作以完成其中任何一个对象都单独无法完成的任务,如Mediator在对象间引入一个mediator对象提供了松耦合所需的间接性;Chain of Responsibility提供了更松的耦
合,它通过一条候选对象链隐式的向一个对象发松请求,可以运行时刻决定哪些候选者参与到链中;Observer定义并保持了对象间的依赖关系;其它的行为对象模式常将行为封装封装在一个对象中,并将请求指派给
它,Strategy模式将算法封装在对象中,这样可以方面的改变和指定一个对象所使用的算法;Command模式将请求封装在对象中,这样它就可以作为参数来传递,已可以存储在历史列表中或以其它方式使用;State
模式封装一个对象的状态,使得当这个对象的状态对象变化时,该对象可改变它的行为;Visitor模式封装分布于多个类之间的行为;而Iterator模式则抽象了访问和遍历一个集合中对象的方式。
Php设计模式(三):行为型模式part2,布布扣,bubuko.com
原文地址:http://www.cnblogs.com/hunhunrensheng/p/3759606.html