本文實(shí)例講述了PHP設(shè)計(jì)模式入門(mén)之狀態(tài)模式原理與實(shí)現(xiàn)方法。分享給大家供大家參考,具體如下:
想必大家都用過(guò)自動(dòng)售賣的自動(dòng)飲料機(jī)吧,塞入硬幣或紙幣,選擇想要的飲料,飲料就會(huì)在機(jī)器的下方滾出。大家有沒(méi)有相關(guān)如果用程序去寫(xiě)一個(gè)飲料機(jī)要怎么樣實(shí)現(xiàn)呢?
首先我們可以分享一下這部飲料機(jī)有幾種狀態(tài)
一、沒(méi)有錢(qián)的狀態(tài)
二、有錢(qián)的狀態(tài)
三、售出的狀態(tài)
四、銷售一空的狀態(tài)
好吧,知道了這些狀態(tài)之后我們開(kāi)始寫(xiě)代碼了!
JuiceMachine.php
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
|
<?php /** * 飲料機(jī) * @author ben * */ class JuiceMachine{ /** * 糖果機(jī)一共存在四種狀態(tài):沒(méi)錢(qián),有錢(qián),成功售出以及銷售一空 * * 沒(méi)錢(qián)的狀態(tài) * @var INT */ const NOMONEY = 0; /** * 有錢(qián)的狀態(tài) * @var INT */ const HASMONEY = 1; /** * 成功售出的狀態(tài) * @var INT */ const SOLD = 2; /** * 銷售一空的狀態(tài) * @var INT */ const SOLDOUT = 3; /** * 記錄糖果機(jī)當(dāng)前的狀態(tài),初始化狀態(tài)為售空 * @var INT */ private $_state = JuiceMachine::SOLDOUT; /** * 該變量用于記錄飲料機(jī)中飲料的數(shù)量 */ private $_count ; /** * 構(gòu)造方法,最主要是用來(lái)初始化count和state屬性的 */ public function __construct( $count ){ $this ->_count = $count ; //當(dāng)飲料機(jī)中的飲料數(shù)量大于零時(shí),將飲料機(jī)的狀態(tài)重置為沒(méi)有錢(qián)的狀態(tài)。 if ( $this ->_count > 0){ $this ->_state = JuiceMachine::NOMONEY; } } /** * 投入硬幣 */ public function insertCoin(){ if ( $this ->_state == JuiceMachine::HASMONEY ){ echo "you can't insert another coin!<br />" ; } elseif ( $this ->_state == JuiceMachine::NOMONEY){ echo "you just insert a coin<br />" ; $this ->_state = JuiceMachine::HASMONEY; } elseif ( $this ->_state == JuiceMachine::SOLD){ echo "wait a minute, we are giving you a bottle of juice<br />" ; } elseif ( $this ->_state == JuiceMachine::SOLDOUT){ echo "you can't insert coin, the machine is already soldout<br />" ; } } /** * 退回硬幣 */ public function retreatCoin(){ if ( $this ->_state == JuiceMachine::HASMONEY ){ echo "coin return!<br />" ; $this ->_state = JuiceMachine::NOMONEY; } elseif ( $this ->_state == JuiceMachine::NOMONEY){ echo "you have'nt inserted a coin yet<br />" ; } elseif ( $this ->_state == JuiceMachine::SOLD){ echo "sorry, you already clicked the botton<br />" ; } elseif ( $this ->_state == JuiceMachine::SOLDOUT){ echo "you have'nt inserted a coin yet<br />" ; } } /** * 點(diǎn)擊飲料對(duì)應(yīng)的按鈕 */ public function clickButton(){ if ( $this ->_state == JuiceMachine::HASMONEY ){ echo "you clicked, we are giving you a bottle of juice...<br />" ; $this ->_state = JuiceMachine::SOLD; //改變飲料機(jī)的狀態(tài)為售出模式 $this ->dispend(); } elseif ( $this ->_state == JuiceMachine::NOMONEY){ echo "you clicked,but you hav'nt inserted a coin yet<br />" ; } elseif ( $this ->_state == JuiceMachine::SOLD){ echo "click twice does'nt get you two bottle of juice<br />" ; } elseif ( $this ->_state == JuiceMachine::SOLDOUT){ echo "you clicked, but the machine is already soldout<br />" ; } } /** * 發(fā)放飲料 */ public function dispend(){ if ( $this ->_state == JuiceMachine::HASMONEY ){ echo "please click the button first<br />" ; } elseif ( $this ->_state == JuiceMachine::NOMONEY){ echo "you need to pay first<br />" ; } elseif ( $this ->_state == JuiceMachine::SOLD){ echo "now you get you juice<br />" ; //飲料機(jī)中的飲料數(shù)量減一 $this ->_count--; if ( $this ->_count <= 0){ echo "opps, runing out of juice<br />" ; //如果這時(shí)飲料機(jī)中沒(méi)有飲料了,將飲料機(jī)的狀態(tài)重置為銷售一空 $this ->_state = JuiceMachine::SOLDOUT; } else { //將飲料機(jī)的狀態(tài)重置為沒(méi)有錢(qián) $this ->_state = JuiceMachine::NOMONEY; } } elseif ( $this ->_state == JuiceMachine::SOLDOUT){ //其實(shí)這種情況不應(yīng)該出現(xiàn) echo "opps, it appears that we don't have any juice left<br />" ; } } } |
index.php
1
2
3
4
5
6
7
|
<?php require_once 'JuiceMachine.php' ; $juiceMachine = new JuiceMachine(1); $juiceMachine ->insertCoin(); $juiceMachine ->clickButton(); |
運(yùn)行的結(jié)果是:
you just insert a coin
you clicked, we are giving you a bottle of juice...
now you get you juice
opps, runing out of juice
到目前為止我們的程序運(yùn)行良好,沒(méi)有出現(xiàn)什么問(wèn)題,但是從這些多重的if判斷中你是否嗅到了壞代碼的味道呢?有一天問(wèn)題終于出現(xiàn)了,老板希望當(dāng)用戶點(diǎn)擊按鈕時(shí)有10%的概率拿到兩瓶飲料,我們需要為飲料機(jī)多加一個(gè)狀態(tài),這時(shí)去修改代碼就成為了一種災(zāi)難,而且很可能會(huì)影響到之前的代碼,帶來(lái)新的bug,看看狀態(tài)模式如何幫助我們度過(guò)難關(guān)吧!
狀態(tài)模式的官方定義是:狀態(tài)模式允許對(duì)象在內(nèi)部狀態(tài)改變是改變它的行為,對(duì)象看起來(lái)好像是修改了它的類
用uml類圖表示如下:
在我們這個(gè)項(xiàng)目中的實(shí)際類圖如下:
具體實(shí)現(xiàn)代碼:
State.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
<?php interface State{ /** * 插入硬幣 */ public function insertCoin(); /** * 回退硬幣 */ public function retreatCoin(); /** * 點(diǎn)擊按鈕 */ public function clickButton(); /** * 發(fā)放飲料 */ public function dispend(); } |
NomoneyState.php
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
|
<?php require_once 'State.php' ; class NomoneyState implements State{ /** * 飲料機(jī)的實(shí)例 * * @var object */ private $_juiceMachine ; /** * 構(gòu)造方法,主要用于初始化飲料機(jī)實(shí)例 * */ public function __construct( $juiceMachine ){ $this ->_juiceMachine = $juiceMachine ; } /* (non-PHPdoc) * @see State::insertCoin() */ public function insertCoin() { // TODO Auto-generated method stub echo "you just insert a coin<br />" ; //將飲料機(jī)的狀態(tài)切換成有錢(qián)的狀態(tài) $this ->_juiceMachine->setState( $this ->_juiceMachine->getHasmoneyState()); } /* (non-PHPdoc) * @see State::retreatCoin() */ public function retreatCoin() { // TODO Auto-generated method stub echo "you have'nt inserted a coin yet<br />" ; } /* (non-PHPdoc) * @see State::clickButton() */ public function clickButton() { // TODO Auto-generated method stub echo "you clicked,but you hav'nt inserted a coin yet<br />" ; } /* (non-PHPdoc) * @see State::dispend() */ public function dispend() { // TODO Auto-generated method stub echo "you need to pay first<br />" ; } } |
HasmoneyState.php
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
|
<?php require_once 'State.php' ; class HasmoneyState implements State { /** * 飲料機(jī)的實(shí)例 * * @var object */ private $_juiceMachine ; /** * 構(gòu)造方法,主要用于初始化飲料機(jī)實(shí)例 */ public function __construct( $juiceMachine ) { $this ->_juiceMachine = $juiceMachine ; } /* * (non-PHPdoc) @see State::insertCoin() */ public function insertCoin() { // TODO Auto-generated method stub echo "you can't insert another coin!<br />" ; } /* * (non-PHPdoc) @see State::retreatCoin() */ public function retreatCoin() { // TODO Auto-generated method stub echo "coin return!<br />" ; $this ->_juiceMachine->setState( $this ->_juiceMachine->getNomoneyState()); } /* * (non-PHPdoc) @see State::clickButton() */ public function clickButton() { // TODO Auto-generated method stub echo "you clicked, we are giving you a bottle of juice...<br />" ; // 改變飲料機(jī)的狀態(tài)為售出模式 $rand = mt_rand(0, 0); // 當(dāng)隨機(jī)數(shù)為0(即1/10的概率)并且飲料機(jī)中還有1瓶以上的飲料時(shí) if ( $rand == 0 && $this ->_juiceMachine->getCount() > 1) { $this ->_juiceMachine->setState( $this ->_juiceMachine->getWinnerState()); } else { $this ->_juiceMachine->setState( $this ->_juiceMachine->getSoldState()); } } /* * (non-PHPdoc) @see State::dispend() */ public function dispend() { // TODO Auto-generated method stub echo "please click the button first<br />" ; } } |
SoldoutState.php
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
|
<?php require_once 'State.php' ; class SoldoutState implements State{ /** * 飲料機(jī)的實(shí)例 * * @var object */ private $_juiceMachine ; /** * 構(gòu)造方法,主要用于初始化飲料機(jī)實(shí)例 * */ public function __construct( $juiceMachine ){ $this ->_juiceMachine = $juiceMachine ; } /* (non-PHPdoc) * @see State::insertCoin() */ public function insertCoin() { // TODO Auto-generated method stub echo "you can't insert coin, the machine is already soldout<br />" ; } /* (non-PHPdoc) * @see State::retreatCoin() */ public function retreatCoin() { // TODO Auto-generated method stub echo "you have'nt inserted a coin yet<br />" ; } /* (non-PHPdoc) * @see State::clickButton() */ public function clickButton() { // TODO Auto-generated method stub echo "you clicked, but the machine is already soldout<br />" ; } /* (non-PHPdoc) * @see State::dispend() */ public function dispend() { // TODO Auto-generated method stub echo "opps, it appears that we don't have any juice left<br />" ; } } |
SoldState.php
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
|
<?php require_once 'State.php' ; class SoldState implements State{ /** * 飲料機(jī)的實(shí)例 * * @var object */ private $_juiceMachine ; /** * 構(gòu)造方法,主要用于初始化飲料機(jī)實(shí)例 * */ public function __construct( $juiceMachine ){ $this ->_juiceMachine = $juiceMachine ; } /* (non-PHPdoc) * @see State::insertCoin() */ public function insertCoin() { // TODO Auto-generated method stub echo "wait a minute, we are giving you a bottle of juice<br />" ; } /* (non-PHPdoc) * @see State::retreatCoin() */ public function retreatCoin() { // TODO Auto-generated method stub echo "sorry, you already clicked the botton<br />" ; } /* (non-PHPdoc) * @see State::clickButton() */ public function clickButton() { // TODO Auto-generated method stub echo "click twice does'nt get you two bottle of juice<br />" ; } /* (non-PHPdoc) * @see State::dispend() */ public function dispend() { $this ->_juiceMachine->decJuice(); if ( $this ->_juiceMachine->getCount() <= 0){ echo "opps, runing out of juice<br />" ; //如果這時(shí)飲料機(jī)中沒(méi)有飲料了,將飲料機(jī)的狀態(tài)重置為銷售一空 $this ->_juiceMachine->setState( $this ->_juiceMachine->getSoldoutState()); } else { //將飲料機(jī)的狀態(tài)重置為沒(méi)有錢(qián) $this ->_juiceMachine->setState( $this ->_juiceMachine->getNomoneyState()); } } } |
WinnerState.php
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
|
<?php require_once 'State.php' ; class WinnerState implements State { /** * 飲料機(jī)的實(shí)例 * * @var object */ private $_juiceMachine ; /** * 構(gòu)造方法,主要用于初始化飲料機(jī)實(shí)例 */ public function __construct( $juiceMachine ) { $this ->_juiceMachine = $juiceMachine ; } /* * (non-PHPdoc) @see State::insertCoin() */ public function insertCoin() { // TODO Auto-generated method stub echo "wait a minute, we are giving you a bottle of juice<br />" ; } /* * (non-PHPdoc) @see State::retreatCoin() */ public function retreatCoin() { // TODO Auto-generated method stub echo "sorry, you already clicked the botton<br />" ; } /* * (non-PHPdoc) @see State::clickButton() */ public function clickButton() { // TODO Auto-generated method stub echo "click twice does'nt get you two bottle of juice<br />" ; } /* * (non-PHPdoc) @see State::dispend() */ public function dispend() { echo "you are a winner! you get two bottle of juice!<br />" ; $this ->_juiceMachine->decJuice(); if ( $this ->_juiceMachine->getCount() > 0) { $this ->_juiceMachine->decJuice(); if ( $this ->_juiceMachine->getCount() <= 0) { echo "opps, runing out of juice<br />" ; // 如果這時(shí)飲料機(jī)中沒(méi)有飲料了,將飲料機(jī)的狀態(tài)重置為銷售一空 $this ->_juiceMachine->setState( $this ->_juiceMachine->getSoldoutState()); } else { // 將飲料機(jī)的狀態(tài)重置為沒(méi)有錢(qián) $this ->_juiceMachine->setState( $this ->_juiceMachine->getSoldoutState()); } } else { echo "opps, runing out of juice<br />" ; // 如果這時(shí)飲料機(jī)中沒(méi)有飲料了,將飲料機(jī)的狀態(tài)重置為銷售一空 $this ->_juiceMachine->setState( $this ->_juiceMachine->getSoldoutState()); } } } |
JuiceMachine.php
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
|
<?php require_once './state/NomoneyState.php' ; require_once './state/HasmoneyState.php' ; require_once './state/SoldState.php' ; require_once './state/SoldoutState.php' ; require_once './state/WinnerState.php' ; class JuiceMachine { /** * 記錄糖果機(jī)當(dāng)前的狀態(tài),初始化狀態(tài)為售空 * * @var object */ private $_state ; /** * 該變量用于記錄飲料機(jī)中飲料的數(shù)量 */ private $_count ; /** * 構(gòu)造方法,最主要是用來(lái)初始化count和state屬性的 */ public function __construct( $count ) { $this ->_state = new SoldoutState( $this ); $this ->_count = $count ; // 當(dāng)飲料機(jī)中的飲料數(shù)量大于零時(shí),將飲料機(jī)的狀態(tài)重置為沒(méi)有錢(qián)的狀態(tài)。 if ( $this ->_count > 0) { $this ->_state = new NomoneyState( $this ); } } /* * (non-PHPdoc) @see State::insertCoin() */ public function insertCoin() { // TODO Auto-generated method stub $this ->_state->insertCoin(); } /* * (non-PHPdoc) @see State::retreatCoin() */ public function retreatCoin() { // TODO Auto-generated method stub $this ->_state->retreatCoin(); } /* * (non-PHPdoc) @see State::clickButton() */ public function clickButton() { $this ->_state->clickButton(); //其實(shí)發(fā)放糖果是在用戶點(diǎn)擊完按鈕后機(jī)器內(nèi)部進(jìn)行的所有沒(méi)有必要再寫(xiě)一個(gè)dispend方法 $this ->_state->dispend(); } /** * 設(shè)置糖果機(jī)的狀態(tài) * * @param State $state */ public function setState(State $state ) { $this ->_state = $state ; } /** * 獲取沒(méi)有錢(qián)的狀態(tài) */ public function getNomoneyState(){ return new NomoneyState( $this ); } /** * 獲取有錢(qián)的狀態(tài) */ public function getHasmoneyState(){ return new HasmoneyState( $this ); } /** * 獲取售出的狀態(tài) */ public function getSoldState(){ return new SoldState( $this ); } /** * 獲取銷售一空的狀態(tài) */ public function getSoldoutState(){ return new SoldoutState( $this ); } /** * 獲取幸運(yùn)者的狀態(tài) */ public function getWinnerState(){ return new WinnerState( $this ); } /** * 獲取飲料機(jī)中飲料的數(shù)量 */ public function getCount(){ return $this ->_count; } /** * 將飲料數(shù)量減一 */ public function decJuice(){ echo "now you get you juice<br />" ; //飲料機(jī)中的飲料數(shù)量減一 $this ->_count--; } } |
index.php
1
2
3
4
5
6
7
|
<?php require_once 'JuiceMachine.php' ; $juiceMachine = new JuiceMachine(2); $juiceMachine ->insertCoin(); $juiceMachine ->clickButton(); |
希望本文所述對(duì)大家PHP程序設(shè)計(jì)有所幫助。
原文鏈接:https://blog.csdn.net/u011250882/article/details/44753867