1. 程式人生 > >設計模式之PHP專案應用——策略模式設計商場收銀系統

設計模式之PHP專案應用——策略模式設計商場收銀系統

1 策略模式簡介

    策略模式定義了一系列的演算法,並將每一個演算法封裝起來,而且使它們還可以相互替換。策略模式讓演算法獨立於使用它的客戶而獨立變化。
    

2 模式組成

    1)抽象策略角色(Strategy):
            策略類,通常由一個介面或者抽象類實現。
    
    2)具體策略角色(ConcreteStrategy):
           包裝了相關的演算法和行為。
    
    3)環境角色(Context):
          持有一個策略類的引用,最終給客戶端呼叫。
    

3 模式核心思想

    策略模式是一種定義一些列演算法的方法,從概念上來看,所有這些演算法完成的都是相同的工作,只是實現不同,它可以以相同的方式呼叫所有的演算法,減少了各種演算法類與使用演算法類的耦合。命令模式的演算法是相互獨立的,每個命令做的工作是不同的。而策略模式卻是在做同一種工作。

4 模式架構圖

 

5 程式架構

1) 抽象策略(Strategy)

// 定義介面,定義了要實現的策略演算法
interface IStrategy{
    // 演算法方法
    public function doFunction();
}


2) 具體策略(ConcreteStrategy)

// 具體A策略
class ConcreteStrategyA implements IStrategy{

    public function doFunction(){
        echo '演算法A實現';
    }
}

// 具體B策略
class ConcreteStrategyB implements IStrategy{

    public function doFunction(){
        echo '演算法B實現';
    }
}

// 具體C策略
class ConcreteStrategyC implements IStrategy{

    public function doFunction(){
        echo '演算法C實現';
    }
}


3)環境類(Context)

// 環境類,維護一個Strategy應用
class Context{
    // 策略
    private $_strategy = null;

    public function __construct(IStrategy $strategy){
        $this->_strategy = $strategy;
    }

    public function doWork(){
        return $this->_strategy->doFunction();
    }
}


4)客戶端(Client)

// 客戶端類
class Client{

    public function main($data){
        // A策略
        $context = new Context(new ConcreteStrategyA());
        $context->doWork();
        
        // B策略
        $context = new Context(new ConcreteStrategyB());
        $context->doWork();
        
        // C策略
        $context = new Context(new ConcreteStrategyC());
        $context->doWork();
    }
}



6 專案應用


6.1 需求說明

    實現一個商場收銀系統,商品可以有正常收費,打折收費,返利收費等模式(來之《大話設計模式》)


6.2 需求分析

    按照需求,可以將收費操作設計成為一個介面演算法,正常收費,打折收費,返利收費都繼承這個介面,實現不同的策略演算法。然後設計一個環境類,去維護策略的例項。


6.3 設計架構圖



6.4 程式原始碼下載

http://download.csdn.net/detail/clevercode/8700009

6.5 程式說明

1)strategy.php

<?php
/**
 * strategy.php
 *
 * 策略類:定義了一系列的演算法,這些演算法都是完成的相同工作,但是實現不同。
 *  
 * 特別宣告:本原始碼是根據《大話設計模式》一書中的C#案例改成成PHP程式碼,和書中的
 * 程式碼會有改變和優化。
 *
 * Copyright (c) 2015 http://blog.csdn.net/CleverCode
 *
 * modification history:
 * --------------------
 * 2015/5/5, by CleverCode, Create
 *
 */

// 定義介面現金策略,每種策略都是具體實現acceptCash,但都是實現收取現金功能
interface ICashStrategy{
    // 收取現金
    public function acceptCash($money);
}

// 正常收取策略
class NormalStrategy implements ICashStrategy{

    /**
     * 返回正常金額
     *
     * @param double $money 金額
     * @return double 金額
     */
    public function acceptCash($money){
        return $money;
    }
}

// 打折策略
class RebateStrategy implements ICashStrategy{
    // 打折比例
    private $_moneyRebate = 1;

    /**
     * 建構函式
     *
     * @param double $rebate 比例
     * @return void
     */
    public function __construct($rebate){
        $this->_moneyRebate = $rebate;
    }

    /**
     * 返回正常金額
     *
     * @param double $money 金額
     * @return double 金額
     */
    public function acceptCash($money){
        return $this->_moneyRebate * $money;
    }
}

// 返利策略
class ReturnStrategy implements ICashStrategy{
    // 返利條件
    private $_moneyCondition = null;
    
    // 返利多少
    private $_moneyReturn = null;

    /**
     * 建構函式
     *
     * @param double $moneyCondition 返利條件
     * @return double $moneyReturn 返利多少
     * @return void
     */
    public function __construct($moneyCondition, $moneyReturn){
        $this->_moneyCondition = $moneyCondition;
        $this->_moneyReturn = $moneyReturn;
    }

    /**
     * 返回正常金額
     *
     * @param double $money 金額
     * @return double 金額
     */
    public function acceptCash($money){
        if (!isset($this->_moneyCondition) || !isset($this->_moneyReturn) || $this->_moneyCondition == 0) {
            return $money;
        }
        
        return $money - floor($money / $this->_moneyCondition) * $this->_moneyReturn;
    }
}






2)   strategyPattern.php
<?php
/**
 * strategyPattern.php
 *
 * 設計模式:策略模式
 * 
 * 模式簡介:
 *     它定義了演算法家族,分別封裝起來,讓它們之間可以互相替換,此模式讓演算法的變化,
 * 不會影響到使用演算法的客戶。
 *     策略模式是一種定義一些列演算法的方法,從概念上來看,所有這些演算法完成的都是
 * 相同的工作,只是實現不同,它可以以相同的方式呼叫所有的演算法,減少了各種演算法類
 * 與使用演算法類的耦合。
 *     本原始碼中的各種結賬方式,其實都是在結賬,但是具體的實現確實不同的。策略模式與
 * 命令模式不同的是,命令模式的演算法是相互獨立的,每個命令做的工作是不同的。而策略模式
 * 卻是在做通一種工作。          
 * 
 * 特別宣告:本原始碼是根據《大話設計模式》一書中的C#案例改成成PHP程式碼,和書中的
 * 程式碼會有改變和優化。
 *
 * Copyright (c) 2015 http://blog.csdn.net/CleverCode
 *
 * modification history:
 * --------------------
 * 2015/5/14, by CleverCode, Create
 *
 */

// 載入所有的策略
include_once ('strategy.php');

// 建立一個環境類,根據不同的需求呼叫不同策略
class CashContext{
    
    // 策略
    private $_strategy = null;

    /**
     * 建構函式
     *
     * @param string $type 型別
     * @return void
     */
    public function __construct($type = null){
        if (!isset($type)) {
            return;
        }
        $this->setCashStrategy($type);
    }

    /**
     * 設定策略(簡單工廠與策略模式混合使用)
     *
     * @param string $type 型別
     * @return void
     */
    public function setCashStrategy($type){
        $cs = null;
        switch ($type) {
            
            // 正常策略
            case 'normal' :
                $cs = new NormalStrategy();
                break;
            
            // 打折策略
            case 'rebate8' :
                $cs = new RebateStrategy(0.8);
                break;
            
            // 返利策略
            case 'return300to100' :
                $cs = new ReturnStrategy(300, 100);
                break;
        }
        $this->_strategy = $cs;
    }

    /**
     * 獲取結果
     *
     * @param double $money 金額
     * @return double
     */
    public function getResult($money){
        return $this->_strategy->acceptCash($money);
    }

    /**
     * 獲取結果
     *
     * @param string $type 型別
     * @param int $num 數量
     * @param double $price 單價
     * @return double
     */
    public function getResultAll($type, $num, $price){
        $this->setCashStrategy($type);
        return $this->getResult($num * $price);
    }
}

/*
 * 客戶端類
 * 讓客戶端和業務邏輯儘可能的分離,降低客戶端和業務邏輯演算法的耦合,
 * 使業務邏輯的演算法更具有可移植性
 */
class Client{

    public function main(){
        $total = 0;
        
        $cashContext = new CashContext();
        
        // 購買數量
        $numA = 10;
        // 單價
        $priceA = 100;
        // 策略模式獲取結果
        $totalA = $cashContext->getResultAll('normal', $numA, $priceA);
        $this->display('A', 'normal', $numA, $priceA, $totalA);
        
        // 購買數量
        $numB = 5;
        // 單價
        $priceB = 100;
        // 打折策略獲取結果
        $totalB = $cashContext->getResultAll('rebate8', $numB, $priceB);
        $this->display('B', 'rebate8', $numB, $priceB, $totalB);
        
        // 購買數量
        $numC = 10;
        // 單價
        $priceC = 100;
        // 返利策略獲取結果
        $totalC = $cashContext->getResultAll('return300to100', $numC, $priceC);
        $this->display('C', 'return300to100', $numC, $priceC, $totalC);
    }

    /**
     * 列印
     *
     * @param string $name 商品名
     * @param string $type 型別
     * @param int $num 數量
     * @param double $price 單價
     * @return double
     */
    public function display($name, $type, $num, $price, $total){
        echo date('Y-m-d H:i:s') . ",$name,[$type],num:$num,price:$price,total:$total\r\n";
    }
}

/**
 * 程式入口
 */
function start(){
    $client = new Client();
    $client->main();
}

start();

?>


3)在strategy.php與strategyPattern.php中。如果需要擴充套件多的策略,只需要繼承收費介面實現更多的類,這裡與簡單工廠模式結合使用。是程式更清晰。



7 總結

7.1 優點:

    1、 策略模式提供了管理相關的演算法族的辦法。策略類的等級結構定義了一個演算法或行為族。恰當使用繼承可以把公共的程式碼轉移到父類裡面,從而避免重複的程式碼。
    2、 策略模式提供了可以替換繼承關係的辦法。繼承可以處理多種演算法或行為。如果不是用策略模式,那麼使用演算法或行為的環境類就可能會有一些子類,每一個子類提供一個不同的演算法或行為。但是,這樣一來演算法或行為的使用者就和演算法或行為本身混在一起。決定使用哪一種演算法或採取哪一種行為的邏輯就和演算法或行為的邏輯混合在一起,從而不可能再獨立演化。繼承使得動態改變演算法或行為變得不可能。
    3、 使用策略模式可以避免使用多重條件轉移語句。多重轉移語句不易維護,它把採取哪一種演算法或採取哪一種行為的邏輯與演算法或行為的邏輯混合在一起,統統列在一個多重轉移語句裡面,比使用繼承的辦法還要原始和落後。


7.2 缺點:

    1、客戶端必須知道所有的策略類,並自行決定使用哪一個策略類。這就意味著客戶端必須理解這些演算法的區別,以便適時選擇恰當的演算法類。換言之,策略模式只適用於客戶端知道所有的演算法或行為的情況。

    2、 策略模式造成很多的策略類,每個具體策略類都會產生一個新類。有時候可以通過把依賴於環境的狀態儲存到客戶端裡面,而將策略類設計成可共享的,這樣策略類例項可以被不同客戶端使用。換言之,可以使用享元模式來減少物件的數量。

1)原創作品,出自"CleverCode的部落格",轉載時請務必註明以下原創地址,否則追究版權法律責任。


相關推薦

設計模式PHP專案應用——策略模式設計商場系統

1 策略模式簡介     策略模式定義了一系列的演算法,並將每一個演算法封裝起來,而且使它們還可以相互替換。策略模式讓演算法獨立於使用它的客戶而獨立變化。     2 模式組成     1)抽象策略角色(Strategy):             策略類,通常由一個介面或

設計模式PHP專案應用——策略模式設計自動駕駛系統

1 前言         關於策略模式的定義,模式組成,模式核心思想,模式架構圖,程式架構等基礎知識介紹。請先參考我的另外一篇部落格《(三)設計模式之PHP專案應用(策略模式:商場收銀系統)》:http://blog.csdn.net/clevercode/article/

讀《大話設計模式》——應用策略模式的"商場系統"(WinForm)

策略模式的結構 這個模式涉及到三個角色: 環境(Context)角色:持有一個 Strategy 類的引用。抽象策略(Strategy)角色:這是一個抽象角色,通常由一個介面或抽象類實現。此角色給出所有的具體策略類所需的介面。具體策略(ConcreteStrategy)角色:包裝了相關的演算法或行為。 &n

設計模式的總結簡單工廠與策略模式

mage 建立 不變 href catch nag 實現類 初步 cti 前言 面向對象編程追求的本質-提高擴展性、可維護性、靈活性和復用性。合理利用面向對象6個原則,能夠很好的達到要求。如何利用好就是至關重要的了,前人總結了23+個設計模式能夠讓初學者更容易

大話設計策略模式實現簡易系統

收銀系統 計算方式 一直會變 今天 是滿300 返100 明天 可能 就是滿 300 返50 我們不可能 一直 去改程式 所以 我們還要 用到反射 來實現 動態的 更改 計算方式  這裡面我 們先建立一下xml檔案 程式碼如下 using System; using Syst

設計禪——靈活的策略模式

一、引言 在平時生活中當我們想要做一件事的時候往往會有許多的途徑和方法,像我們去公司上班,可以走路去,也可以騎車或者開車去;還有像吃飯,我們可以選擇自己做飯吃,也可以出去吃,臉長得好看的還能讓人請吃飯等等,但無論選擇哪種方式,我們最終達到的目的結果都是一樣的,只

設計模式】Java服務開發應用策略模式的一個例子

當我們寫程式碼時遇到了需要if else 需要實現的問題時,就可以考慮是否引入某種設計模式,能讓程式碼寫得更加graceful。 假設我們現在有個設計使用者查詢的RESTful介面的需求,使用者可能有多個屬性,有id,firstName ,lastName,age,adr

Php設計模式【迭代器模式Iterator Pattern】

概述 迭代器(Iterator)模式,又叫做遊標(Cursor)模式。GOF給出的定義為:提供一種方法訪問一個容器(container)物件中各個元素,而又不需暴露該物件的內部細節。 案例 黑棗電視公司的在生產的電視機,使用遙控器[後一個]和[前一個]按鈕調節頻道。當按下[

PHP設計模式直譯器(Interpreter)模式瞭解下

直譯器模式,它是什麼呢? 意思就是,給定一個語言, 定義它的文法的一種表示,並定義一個直譯器,該直譯器使用該表示來解釋語言中的句子,這是最實在的一種說法。 我們還可以理解為它是用於分析一個實體的關鍵元素,並且針對每個元素提供自己的解釋或相應動作。直譯器模式非常常用,比如P

設計模式六:工廠方法模式(Factory method Pattern)

image bsp turn stat ole ati ace 方法 系統擴展 工廠方法(Factory Method)模式就是定義一個創建對象的工廠接口,將實際創建工作推遲到子類當中。 核心工廠類不再負責具體產品的創建,僅提供了具體工廠子類必須實現的接口,這樣核

設計模式結構型-適配器模式(Adapter)

request 不同之處 設計模式 wid date 結構 lap target err (一)定義:將一個接口轉換成為客戶想要的另一個接口,適配器模式使接口不兼容的那些類可以一起工作。 1.1 UML類圖 1.2 類與對象之間關系 Target:目錄抽象類,定義客戶

設計模式(十七)---策略模式

封裝 客戶端 else 互換 rip oid 接口 相同 角色 1、簡介   策略模式屬於對象的行為模式。其用意是針對一組算法,將每一個算法封裝到具有共同接口的獨立的類中,從而使得它們可以相互替換。策略模式使得算法可以在不影響到客戶端的情況下發生變化。 2、策略模式的結構

C#設計模式五創建者模式(Builder)【創建型】

包含 direct linq 自然 解釋 並且 宋體 主板 但是 一、引言 今天我們要講講Builder模式,也就是建造者模式,當然也有叫生成器模式的。在現實生活中,我們經常會遇到一些構成比較復雜的物品,比如:電腦,它就是一個復雜的物品,它主要是由CPU、主板、硬盤、顯卡

Java設計模式(8)——創建型模式合成(組合)模式

span color java設計 合成 src 一致性 rdquo img spa 一、概述   定義   將對象以樹形結構組織起來,以達成“部分-整體” 的層次結構,使得客戶端對單個對象和組合對象的使用具有一致性。   簡圖    J

C#設計模式十七中介者模式(Mediator Pattern)【行為型】

[] 過多 深入 理解 申請 代碼實現 控制 name 缺點 原文:C#設計模式之十七中介者模式(Mediator Pattern)【行為型】一、引言 今天我們開始講“行為型”設計模式的第五個模式,該模式是【中介者模式】,英文名稱是:Mediator Pattern。還

C#設計模式十六觀察者模式(Observer Pattern)【行為型】

ngx 現實生活 松耦合 mon html 機制 account current 很好 原文:C#設計模式之十六觀察者模式(Observer Pattern)【行為型】一、引言 今天是2017年11月份的最後一天,也就是2017年11月30日,利用今天再寫一個模式,爭取

C#設計模式十一享元模式(Flyweight Pattern)【結構型】

eal 客戶 來看 滿足 對象狀態 英文 輔助 3.3 fig 原文:C#設計模式之十一享元模式(Flyweight Pattern)【結構型】一、引言 今天我們要講【結構型】設計模式的第六個模式,該模式是【享元模式】,英文名稱是:Flyweight Pattern。還

C#設計模式二十三解釋器模式(Interpreter Pattern)【行為型】

要求 ict string 技術 get protect dict site 關鍵字 原文:C#設計模式之二十三解釋器模式(Interpreter Pattern)【行為型】一、引言 今天我們開始講“行為型”設計模式的第十一個模式,也是面向對象設計模式的最後一個模式,先

C#設計模式二十一訪問者模式(Visitor Pattern)【行為型】

href 集中 動態 元素 lis 聲明 風格 on() 封裝 原文:C#設計模式之二十一訪問者模式(Visitor Pattern)【行為型】一、引言 今天我們開始講“行為型”設計模式的第九個模式,該模式是【訪問者模式】,英文名稱是:Visitor Pattern。如

C#設計模式二十二備忘錄模式(Memento Pattern)【行為型】

his 備忘錄 很好 car 人的 成功率 構圖 設計模式的 就會 原文:C#設計模式之二十二備忘錄模式(Memento Pattern)【行為型】一、引言 今天我們開始講“行為型”設計模式的第十個模式,該模式是【備忘錄模式】,英文名稱是:Memento Pattern