狀態模式從字面上其實並非很好理解。這裏的狀態是什麼意思呢?保存狀態?那不就是備忘錄模式了。其實,這裏的狀態是類的狀態,經過改變類的某個狀態,讓這個類感受像是換了一個類同樣。提及來有點拗口吧,先學習概念以後再看。php
GoF定義:容許一個對象在其內部狀態改變時改變它的行爲。對象看起來彷佛修改了它的類git
GoF類圖github
代碼實現設計模式
class Context {
private $state;
public function SetState(State $state): void {
$this->state = $state;
}
public function Request(): void {
$this->state = $this->state->Handle();
}
}
複製代碼
一個上下文類,也能夠看做是目標類,它的內部有一個狀態對象。當調用Request()的時候,去調用狀態類的Handle()方法。目的是當前上下文類狀態的變化都由外部的這個狀態類來進行操縱。架構
interface State {
public function Handle(): State;
}
class ConcreteStateA implements State {
public function Handle(): State {
echo '當前是A狀態', PHP_EOL;
return new ConcreteStateB();
}
}
class ConcreteStateB implements State {
public function Handle(): State {
echo '當前是B狀態', PHP_EOL;
return new ConcreteStateA();
}
}
複製代碼
抽象狀態接口及兩個具體實現。這兩個具體實現其實是在相互調用。實現的效果就是上下文類每調用一次Request()方法,內部的狀態類就變成別一個狀態。就像一個開關,在打開與關閉中來回切換同樣。學習
$c = new Context();
$stateA = new ConcreteStateA();
$c->SetState($stateA);
$c->Request();
$c->Request();
$c->Request();
$c->Request();
複製代碼
客戶端的實現,實例化上下文對象並設置初始的狀態,而後經過不停的調用Request()對象來實現開關狀態的切換。this
咱們的手機系統內定製了本身的商城系統,能夠在手機上方便的下單購買咱們的商品。一個訂單(Context)會有多種狀態(State),好比未支付、已支付、訂單完成、訂單退款等等一大堆狀態。咱們把這些狀態都放在了對應的狀態類裏去實現,不一樣的狀態類都會再去調用該狀態下一步的動做,好比已支付後就等待收貨、退款後就等待買家填寫物流單號等,這樣,狀態模式就在咱們的商城中被靈活的運用起來咯!!spa
完整代碼:github.com/zhangyue050…架構設計
一般的商城應用中都會有會員體系的存在,通常等級越高的會員能夠享受的折扣也會越多,這個時候,運用狀態模式就能很輕鬆的得到會員的等級折扣。固然,最主要的是,使用狀態模式能夠在須要添加或者刪除會員等級時只添加對應的會員折扣狀態子類就能夠了。其餘業務代碼都不須要變更,咱們一塊兒來看看具體實現吧!設計
會員折扣圖
<?php
class Member {
private $state;
private $score;
public function SetState($state) {
$this->state = $state;
}
public function SetScore($score) {
$this->score = $score;
}
public function GetScore() {
return $this->score;
}
public function discount() {
return $this->state->discount($this);
}
}
interface State {
public function discount($member);
}
class PlatinumMemeberState implements State {
public function discount($member) {
if ($member->GetScore() >= 1000) {
return 0.80;
} else {
$member->SetState(new GoldMemberState());
return $member->discount();
}
}
}
class GoldMemberState implements State {
public function discount($member) {
if ($member->GetScore() >= 800) {
return 0.85;
} else {
$member->SetState(new SilverMemberState());
return $member->discount();
}
}
}
class SilverMemberState implements State {
public function discount($member) {
if ($member->GetScore() >= 500) {
return 0.90;
} else {
$member->SetState(new GeneralMemberState());
return $member->discount();
}
}
}
class GeneralMemberState implements State {
public function discount($member) {
return 0.95;
}
}
$m = new Member();
$m->SetState(new PlatinumMemeberState());
$m->SetScore(1200);
echo '當前會員' . $m->GetScore() . '積分,折扣爲:' . $m->discount(), PHP_EOL;
$m->SetScore(990);
echo '當前會員' . $m->GetScore() . '積分,折扣爲:' . $m->discount(), PHP_EOL;
$m->SetScore(660);
echo '當前會員' . $m->GetScore() . '積分,折扣爲:' . $m->discount(), PHP_EOL;
$m->SetScore(10);
echo '當前會員' . $m->GetScore() . '積分,折扣爲:' . $m->discount(), PHP_EOL;
複製代碼
說明
狀態模式其實運用的範圍很廣,但使用的人確很少。畢竟if...else...更加的直觀,並且大部分平常應用中的狀態通常也不多會去修改或添加。若是你的訂單狀態須要常常的修改或添加,那確定在架構設計中存在着問題。可是,經過這個模式的學習,咱們看到了面向對象在處理這種問題時所展示的威力,這纔是咱們對設計模式學習的最終目的,靈活合適地運用,更深刻的瞭解面向對象。好了,最後一個設計模式就要登場了,它就是訪問者模式。