PHP設計模式之狀態模式

PHP設計模式之狀態模式

狀態模式從字面上其實並非很好理解。這裏的狀態是什麼意思呢?保存狀態?那不就是備忘錄模式了。其實,這裏的狀態是類的狀態,經過改變類的某個狀態,讓這個類感受像是換了一個類同樣。提及來有點拗口吧,先學習概念以後再看。php

Gof類圖及解釋

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

  • 看出門道了嘛?這裏把狀態的變化給封裝到外部的實現類去了,並非這個上下文或者目標類內部來進行狀態的切換了
  • 那麼狀態模式的意義呢?這個默認類圖的例子過於簡單,其實狀態模式的真正目的是爲了解決複雜的if嵌套問題的,把複雜的if嵌套條件放到一個個的外部狀態類中去判斷,在後面的實例中咱們會看到
  • 適用於:一個對象的行爲取決於它的狀態,而且它的必須在運行時刻根據狀態改變本身的行爲;一個操做中含有大量的多分支條件語句,且這些分支依賴於該對象的狀態;
  • 狀態模式的特色是:它將與特定狀態相關的行爲局部化;它使得狀態轉換顯式化;State對象能夠被共享;
  • 常見於訂單系統、會員系統、OA系統中,也就是流程中會出現各類狀態變化的狀況,均可以使用狀態模式來進行總體的設計與架構

咱們的手機系統內定製了本身的商城系統,能夠在手機上方便的下單購買咱們的商品。一個訂單(Context)會有多種狀態(State),好比未支付、已支付、訂單完成、訂單退款等等一大堆狀態。咱們把這些狀態都放在了對應的狀態類裏去實現,不一樣的狀態類都會再去調用該狀態下一步的動做,好比已支付後就等待收貨、退款後就等待買家填寫物流單號等,這樣,狀態模式就在咱們的商城中被靈活的運用起來咯!!spa

完整代碼:github.com/zhangyue050…架構設計

實例

一般的商城應用中都會有會員體系的存在,通常等級越高的會員能夠享受的折扣也會越多,這個時候,運用狀態模式就能很輕鬆的得到會員的等級折扣。固然,最主要的是,使用狀態模式能夠在須要添加或者刪除會員等級時只添加對應的會員折扣狀態子類就能夠了。其餘業務代碼都不須要變更,咱們一塊兒來看看具體實現吧!設計

會員折扣圖

會員折扣狀態模式版

完整源碼: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;

複製代碼

說明

  • 若是不使用狀態模式,在Member的discount()方法中,咱們可能須要寫不少層if...else...判斷條件
  • 同時,這也帶來了方法體會愈來愈長,愈來愈難以維護的問題
  • 狀態模式正是爲了解決這個問題而存在的
  • 當discount()行爲的結果依賴於Member對象自己的狀態(會員分)時,狀態模式就是最佳的選擇了,也就是上面所說的一個對象的行爲取決於它的狀態

下期看點

狀態模式其實運用的範圍很廣,但使用的人確很少。畢竟if...else...更加的直觀,並且大部分平常應用中的狀態通常也不多會去修改或添加。若是你的訂單狀態須要常常的修改或添加,那確定在架構設計中存在着問題。可是,經過這個模式的學習,咱們看到了面向對象在處理這種問題時所展示的威力,這纔是咱們對設計模式學習的最終目的,靈活合適地運用,更深刻的瞭解面向對象。好了,最後一個設計模式就要登場了,它就是訪問者模式

相關文章
相關標籤/搜索