(三)设计模式之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的博客",转载时请务必注明以下原创地址,否则追究版权法律责任。

2)原创地址:http://blog.csdn.net/clevercode/article/details/45722661(转载务必注明该地址)。

3)欢迎大家关注我博客更多的精彩内容:http://blog.csdn.net/CleverCode

时间: 2024-10-12 20:14:21

(三)设计模式之PHP项目应用(策略模式:商场收银系统)的相关文章

(四)设计模式之PHP项目应用(策略模式:自动驾驶系统)

1 前言 关于策略模式的定义,模式组成,模式核心思想,模式架构图,程序架构等基础知识介绍.请先参考我的另外一篇博客<(三)设计模式之PHP项目应用(策略模式:商场收银系统)>:http://blog.csdn.net/clevercode/article/details/45722661. 2 项目应用 2.1 需求说明 某公司是福特和本田公司的金牌合作伙伴,现要求开发一套自动驾驶系统,只要汽车上安装该系统就可以实现无人驾驶,只用实现启动,转弯,停止功能即可.该系统可以在福特和本田车上使用.这

设计模式总结篇系列:策略模式(Strategy)

前面的博文中分别介绍了Java设计模式中的创建型模式和结构型模式.从本文开始,将分别介绍设计模式中的第三大类,行为型模式.首先我们了解下分为此三大类的依据. 创建型模式:主要侧重于对象的创建过程: 结构型模式:主要侧重于处理类或对象的组合: 行为型模式:主要侧重于类或对象之间的交互以及职责分配. 首先了解下策略模式的概念:定义了多个算法,并将它们封装起来(一般的是每个算法封装成一个单独的类),让算法独立于客户端而可以单独变化. 具体可以看一下下面的例子(以计算加.减.乘为例): 1. 对加.减.

设计模式 ( 十九 ):Strategy策略模式 -- 行为型

设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查找.排序等,一种常用的方法是硬编码(Hard Coding)在一个类中,如需要提供多种查找算法,可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法:当然也可以将这些查找算法封装在一个统一的方法中,通过if…else…或者case等条件判断语句来进行选择.这

设计模式之第8章-策略模式(Java实现)

设计模式之第8章-策略模式(Java实现) “年前大酬宾了啊,现在理发冲500送300,冲1000送500了.鱼哥赶紧充钱啊,理发这事基本一个月一回,挺实惠的啊.不过话说那个理发店的老板好傻啊,冲1000才送500,不如冲两次500,这样可以送600呢.”“这只能说明你不是很笨,但是也算不上聪明.”“啊?难道我想错了?”“这是一种策略,策略,懂?他如果是冲1000送700的话你是不是很大的可能性冲500?而不是1000,但是如果这样的话,在“聪明人”,对,没错,就是你这样的人来说,冲两次500表

设计模式(一)学习----策略模式

策略设计模式:定义一组算法,将每个算法都分装起来,并使他们之间可以互换. 策略模式就是使用的面向对象思想中的继承和多态的机制 策略模式的通用类图: Context类:Strategy类,并且和Strategy类是整体和个体的关系,即聚合关系.对策略角色个体进行封装. Strategy接口:定义这个策略或算法必须有的方法和属性. ConcreteStrategy1,ConcreteStrategy2具体策略角色实现类.实现抽象策略中的方法,该类中含有具体的算法. 上图变成Java代码: 抽象的策略

设计模式之策略模式在地铁票价系统中的应用

引言 设计模式是面向对象编程的一个非常精彩的部分.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性,它能帮助我们将应用组织成容易了解,容易维护,具有弹性的架构.本文通过一个简单的案例来讲述策略模式在地铁票价系统中的应用. 案例描述 乘客从一个车站乘坐地铁到另一个车站,他/她需要购买一张票.铁路部门对于票价有一些特别的票价规定: 按照市物价主管部门批复的轨道交通网络票价体系,即:轨道交通实行按里程计价的多级票价,0~6公里3元,6公里之后每10公里增加1元;票价计算采用最短路径

《大话设计模式》c++实现 之策略模式

一.UML图   二.概念 策略模式:他定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户.   三.优点 (1)策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,他可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合. (2)策略模式的Strategy类曾是为Context定义了一些列的可供重用的算法或行为.集成有助于析取出这些算法中的公共功能. (3)策略模式简化了单元测试,因为

C#设计模式——简单工厂模式实现:超市收银系统

一.超市收银系统: 在上一篇中简单介绍了简单工厂模式,在理论方面应该清楚了这是个什么东西用来处理什么情况和它的优缺点,现在来看看应用简单工厂模式的一个现实情境--超市收银系统.在现实生活中商品.仓库.超市.顾客就是一条链子,通过这条链子不论是顾客买商品或者是超市管理商品都得到非常方便的效果,超市也会有一些优惠的方案,这次我们就通过简单工厂模式来实现我们现实生活中超市收银的情况. 二.逻辑思路: 1.产品: 1-1.创建产品父类,产品有价格.名称.ID等公共属性. 1-2.创建各产品子类,继承于产

二、策略模式-商场促销活动

以商场收银为例,理解并实践"策略模式". 简单商场促销活动描述:营业员提供商品单价.数量.商场目前的活动(满减.打折等),计算用户最终需要支付的金额. 一.面向过程的实现方式 1 package secondStrategy; 2 import java.text.DecimalFormat; 3 public class StrategyTest { 4 public static void main(String[] args) { 5 // 营业员提供信息 6 double to