PHP设计模式之装饰者模式

介绍php

装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。设计模式

 

思惟导图框架

装饰者模式

 

有这样一个项目,作一个餐厅订餐系统。起初的代码结构是这样的。前面有不少Beverage的继承类,如今遇到的问题是牛奶的价钱上涨了,那么全部相关的类,咱们都要进行调整,好比Milk,SugarAndMilk类,这种类还有不少,咱们须要逐个去修改类中的方法——开发人员每次都作这种事情,要疯了!因此咱们要改变现有的结构。如下的图都是简图,实际的图,可没有这么简单。this

 

 

 设计问题:spa

1》类数量爆炸,有不少类,难以维护;设计

2》整个设计呆板;code

3》基类加入的新功能没法使用于子类;对象

 

复用类方法的方式不少,好比继承,组合,委托。为何总是习惯用继承呢?我看Zend Framework也有这种习惯!每次找对应方法,一直往上翻。——题外话!!!!blog

 

 后来通过小组研究决定,咱们决定把基础类抽出来,好比,咱们把咖啡作成一个单独的类,其余的咖啡,好比牛奶咖啡,甜味咖啡,咱们只对材料单独包装成一个类。继承

通过改良的设计:

 

详解

1》对于饮品,咱们直接继承Beverage类,直接把报价写进饮品类里面;

2》而对于一些须要添加调味品的特殊饮品,咱们作累加操做。好比,我想要杯奶咖啡,则 总价=咖啡价+奶价

3》这样不一样的饮料就很容易知道它的价格。

 

代码

 

<?php

abstract class Beverage{

    public $_name;

    abstract public function Cost();

}

// 被装饰者类

class Coffee extends Beverage{

    public function __construct(){

        $this->_name = 'Coffee';

    }  

    public function Cost(){

        return 1.00;

    }  

}

// 如下三个类是装饰者相关类

class CondimentDecorator extends Beverage{

    public function __construct(){

        $this->_name = 'Condiment';

    }  

    public function Cost(){

        return 0.1;

    }  

}

 

class Milk extends CondimentDecorator{

    public $_beverage;

    public function __construct($beverage){

        $this->_name = 'Milk';

        if($beverage instanceof Beverage){

            $this->_beverage = $beverage;

        }else

            exit('Failure');

    }  

    public function Cost(){

        return $this->_beverage->Cost() + 0.2;

    }  

}

 

class Sugar extends CondimentDecorator{

    public $_beverage;

    public function __construct($beverage){

        $this->_name = 'Sugar';

        if($beverage instanceof Beverage){

            $this->_beverage = $beverage;

        }else{

            exit('Failure');

        }

    }

    public function Cost(){

        return $this->_beverage->Cost() + 0.2;

    }

}

 

// Test Case

//1.拿杯咖啡

$coffee = new Coffee();

 

//2.加点牛奶

$coffee = new Milk($coffee);

 

//3.加点糖

$coffee = new Sugar($coffee);

 

printf("Coffee Total:%0.2f元\n",$coffee->Cost());

 

 

总结

 

1.装饰者(Milk)和被装饰者(Coffee)必须是同样的类型。目的是装饰者必须取代被装饰者。

2.添加行为:当装饰者和组件组合时,就是在加入新的行为。

 

题外话:

1.利用继承设计子类行为,是在编译时静态决定的,并且全部的子类都会继承到相同的行为。打个比方,老子想学点功夫,看你小子会太极拳,老子只须要继承你一下 ,老子也就会太极拳了——呵呵,这时老子就变成你儿子了,看来继承是要付出代价的。

 

2.组合,咱们能够扩展对象的行为,在运行时动态地进行扩展。利用组合咱们能够随时把咱们当时设计超类时没有想到的方法加入到对象中,而不用改变现有的代码。打个比方,老子如今没有内力,吸功大法,把和尚,尼姑,道士的内力(行为对象)都吸过来,那在搏斗(运行时)中,老子能够随时都能使用不一样的内力,但也不能胡乱吸内力,不然你就要走火入魔了!

 

3.类应该对扩展开放,对修改关闭。若是咱们每一个部分都用装饰者模式进行设计,那么对于整个框架来讲有点浪费,并且你也加大了代码的难度。那何时使用这种模式呢?咱们通常用于常常改变的地方。那咱们又怎么知道哪些是常常改变的地方呢?这个就须要咱们的经验和你对所处行业的了解。建议你们平时多看点例子。

 

4.装饰模式为设计注入弹性,但同时会在设计中加入大量的小类,这偶尔会致使别人不容易了解这种设计。

 

5.在使用装饰者模式的时候,对插入的的装饰者要特别当心。由于装饰者模式依赖某种特定的类型(Beverage)。

 

6.要想很好的使用装饰者模式,咱们还要配合使用工厂模式和生成器模式,但今天只说装饰者模式。要想知道更多,请听下回分解。

 

 

参考文献:《head first 设计模式》

相关文章
相关标签/搜索