除非注明转载,否则本博客文章皆为原创。 MSN: wfnlxp@hotmail.com QQ: 176564452

深入浅出PHP面向对象与设计模式6

上一篇 / 下一篇  2008-02-02 17:28:32 / 个人分类:面向对象

六、锦囊妙计--策略模式

1、恐龙函数

我们看一个很简单的电子商务网站的功能:

1、普通会员,商品不打折。

2、高级会员,商品打9折。

3、vip会员,商品打8折。

我们可能会这样设计代码

例:6_1

<?php
//打折类
class discountor
{
    public function getDiscount($rank)
    {
        switch ($rank) {
            case 'common':
                $discount = 1;
                break;
            case 'advance':
                $discount = 0.9;
                break;
            case 'vip':
                $discount = 0.8;
                break;
        }
        return $discount;
    }
}
$discountor = new discountor();
echo $discountor->getDiscount('advance');
?>

现在由于每个等级的折扣,不需要计算,所以看起来还是很简单的。

如果$discount不是那么简单出来的,需要分析,比如最近我们给vip的折扣是否有促销,或者这款产品本身是否有特别优惠。

那么这个代码将非常长,这个getDiscount函数的代码也会超长。

等写好这个类的代码,你会发现似乎这不是一个类,而是一个巨大的函数。

我们定义了一个恐龙般巨大的函数,如果一旦不同等级的计算方法发生变动,这个getDiscount函数的修改将是一场噩梦。

 

2、恐龙类

前面我们搞了一个巨型函数,我们先设法优化这个函数的代码,至少便于修改这个函数。

其实我们分析这个函数,由于switch,其实分三个情况来计算折扣,那么我们想到将三个情况的计算,分到不同的函数。

例:6_2

<?php
//打折类
class discountor
{
    public function getDiscount($rank)
    {
            switch ($rank) {
                   case 'common':
                       $discount = $this->getCommonDiscount();
                       break;
                   case 'advance':
                       $discount = $this->getAdvanceDiscount();
                       break;
                   case 'vip':
                       $discount = $this->getVipDiscount();
                       break;
        }
        return $discount;
    }

    protected function getCommonDiscount()
    {
                $discount = 1;
                return $discount;
    }

    protected function getAdvanceDiscount()
    {
                $discount = 0.9;
                return $discount;
    }

    protected function getVipDiscount()
    {
                $discount = 0.8;
                return $discount;
    }
}
$discountor = new discountor();
echo $discountor->getDiscount('advance');
?>

这样一来,我们只要修改相关的函数,就可以完成某种级别用户的折扣计算。

不过还是有个问题,这个类太大了,几个和级别相关的函数里面承担了太大的业务处理。

我们消灭了一个恐龙般的函数,但是这个类还是恐龙类。

 

3、锦囊妙计

前面我们分拆函数getDiscount的时候,已经有了思路,就是拆开一些代码来简化。

在三国演义中,赵云身上带着的锦囊,在不同情况下拆开来解决问题,其实就是封装的思路。

我们不必把discountor当作锦囊,而是把他当作赵云,做几个锦囊类来给赵云用。

例:6_3

<?php
//打折接口
interface IDiscountor
{
    public function getDiscount();
}
//普通用户打折类
class commonDiscountor implements IDiscountor
{
    public function getDiscount()
    {
        $discount = 1;
        return $discount;
    }
}
//高级用户打折类
class advanceDiscountor implements IDiscountor
{
    public function getDiscount()
    {
        $discount = 0.9;
        return $discount;
    }
}
//vip用户打折类
class vipDiscountor implements IDiscountor
{
    public function getDiscount()
    {
        $discount = 0.8;
        return $discount;
    }
}
//打折类
class discountor
{
    public function getDiscount($rank)
    {
        switch ($rank) {
        case 'common':
            $discountor = new commonDiscountor();
            break;
        case 'advance':
            $discountor = new advanceDiscountor();
            break;
        case 'vip':
            $discountor = new vipDiscountor();
            break;
        }
        return $discountor->getDiscount();
    }

}
$discountor = new discountor();
echo $discountor->getDiscount('advance');
?>

这个就是策略模式Strategy),将不同情况的算法分拆到不同的类(比如advanceDiscountor类),然后调用者(discountor类)根据具体的情况,用算法类的对象来处理。

思考:

策略模式是一种常用的模式,我们可以用它来封装不同情况下的算法代码,方便修改。

但是策略模式,如果乱用,那么就会出来很多多余的算法类,也就是分拆过度。

另外,策略类一般直接用new来新建对象调用算法,他与类名是用比较高的关联度,所以有时候,需要考虑用工厂或其他方法来进一步优化。

备注:本文涉及代码,在《phper》第八期中。另外在上海一月份的活动中,我对策略模式进行了更深入的探讨,具体资料请关注论坛pea版块的上海一月份活动总结贴。


TAG: PHP 设计模式 面向对象 策略模式 Strategy

 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

Open Toolbar