装饰模式,动态的给一个对象添加一些额外的职责,就增加的功能来说,装饰模式比生成子类更为灵活。设计模式之装饰模式。每个装饰对象的实现和如何使用这个对象分离了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链中。

<?php
abstract class Component{
    public function operation(){

    }
}
class ConcreteComponent extends Component{
    public function operation(){
        echo '具体对象操作';
    }
}

abstract class Decorator extends Component{
    protected $component;
    public function setComponet($objComponent){
        $this->component = $objComponent;
    }
    public function sonOperation(){
        if(empty($this->component)){
            $this->operation();
        }
    }
}
class ConcreteDecoratorA extends Decorator{
    private $addState;
    public function concteteOperation(){
        $this->operation();
        $this->addState = 'New State';
        echo '具体装饰对象A的操作';
    }
}
class ConcreteDecoratorB extends Decorator{
    public function concreteOperation(){
        $this->operation();
        $this->addBehavior();
        echo '具体操作对象B的操作';
    }
    public function addBehavior(){

    }
}
$cObj = new ConcreteComponent();
$d1Obj = new ConcreteDecoratorA();
$d2Obj = new ConcreteDecoratorB();
//装饰的方法是,先实例化对象c,用d1包装c,用d2包装d1,最终通过d2来执行operation
$d1Obj->setComponet($cObj);
$d2Obj->setComponet($d1Obj);
$d2Obj->sonOperation();
?>

装饰模式是为已有的功能动态的添加更多功能的一种方式。当系统需要新功能的时候,是向旧类中添加新代码。这些新代码通常装饰了原有的类的核心职责或主要行为。新加入的代码仅仅是在满足一定特定条件下才会被需要。而装饰模式提供了一个解决方案。把每个要装饰的功能放在单独类中。需要执行特殊行为时,客户端代码可以有选择的有顺序的去使用装饰功能包装对象。
装饰模式就是把类中的装饰功能删掉,简化原类,把核心职责和装饰区分开。
场景:数据加密和数据过滤是我们在写入数据库前要做的工作,那么先加密再过滤和先过滤再加密,结果肯定是不一样的。所以,保证加密和过滤这2个类彼此独立,如果使用,在客户端进行不同的组合。

依赖倒转原则,是面向对象的标识,以里氏代换原则为基础,使的开放-封闭原则的实现成为了可能。针对接口的而不是针对实现编程。
场景:高内聚低耦合的计算机主机,上篇中提到过的例子http://www.lanecn.com/article/main/aid-18。内存坏了可以直接拔掉换一个新的,不会说华硕的主板就不能插你刚从戴尔的主板上拔下的内存。所以,内存条的设计是针对接口的,是一个统一的标准接口,不是一个主板厂商提供一个接口方式。再所以一下,内存条的设计不是为了实现而去设计的,如果是为了实现,那么我现在要实现它插在戴尔主板上的内存条,它在华硕主板就不能用了。由此,引出一个原则“依赖倒转原则”。
依赖倒转原则:针对接口编程,而不是针对实现编程。高层模块不能依赖于底层模块,而是两者都共同依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
新手总是面向过程的开发,把常用的函数都写成底层的函数。比如数据库操作函数。客户端直接调用数据库操作函数。那么假如有一天客户要求更改数据库呢?就要修改底层的数据库操作函数,但是,<a href="http://www.lanecn.com/article/main/aid-18">面向对象的洗礼:设计模式(四)之开放-封闭原则</a>,对修改是封闭的,不应该用修改的方式,而是用扩展的方式,把相同的操作函数都抽象出来。所以是针对接口,而不是针对实现。另一个原则为针对接口的编程在修改时不需要修改代码,而是扩展的开放-封闭原则提供了实现的原理保障。
里氏代换原则:子类继承父类,则子类可以完全代替父类的所有功能,而不会被使用者察觉。
对于外部只能调用父类的所有public方法,子类则都可以继承过来。
里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:
2、子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
3、子类中可以增加自己特有的方法。
4、当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
5、当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

反面案例:收音机!芯片,喇叭什么的一大堆焊接在一起,超高的耦合度!

开放-封闭原则,是面向对象的核心思想,使用开放-封闭原则的设计模式,可以获得那些声称使用面向对象可以获得的巨大好处,即可扩展性,易维护性,高复用性,超灵活性。
开放原则:对扩展时开放的!
封闭原则:对修改时关闭的!
就是说,一个良好的类,欢迎其他的类去继承它,使用它。但是,不欢迎对它进行修改。如果要修改,以便实现新功能,那么,不如去新开发一个类。当然,绝对的不修改是不可能的。这就要求在开发中多思考,多考虑将来有可能面对的修改,降低对某个特定功能的耦合度。
请注意,开放-封闭原则在OOP中的地位,是核心思想!
扩展性:容易新增多个软件包;
维护性:维护时只需要修改一个类中的一个函数即可,完全不会涉及到其他的代码;
复用性:随时随地,拿来就用;
灵活性:因为可以扩展,容易维护,可以复用,所以灵活。
举例:一台电脑,内存条坏了只需要拔下内存条即可,显卡需要升级只需要拔下旧显卡,插上新显卡。CPU风扇坏了只需要更换风扇而不需要更换CPU。无论是Inter还是AMD,每一小块芯片都有许多的复杂的指令集,我们不需要知道。内存条厂商也不需要知道CPU和主板的指令集,将内存条根据针脚插入主板中,就可以工作,因为它依靠针脚(接口)来传输数据。各个硬件之间相互独立。对某个硬件而言,对内我的指令集和工作方式是封闭的,你不可以修改也不需要知道,对外,我有接口,支持扩展,大家可以把我插了就用。这就是开放-封闭原则的体现。是高聚能低耦合的典型例子。

面向对象的软件开发中,有一个基本原则,那就是单一原则,是设计模式的重点。单一原则,功能单一的类,避免万能类。如果一个类的空能多于一点,就应该拆分成2个类。是面向对象的设计模式中最重要的一个原则。
举个例子,在智能手机刚刚出现的时候,诺基亚占据世界大半壁江山。智能手机可以打电话,发短信,浏览网页,玩游戏,拍照,录像等等,但是,拿拍照来说,拍照比不过傻瓜相机(如今也比不过单反)。尽管将大量的功能融合为一台设备,携带和充电更方便,但是效果并不如单一功能的强大。这就引入了“单一原则”。
在软件开发过程中,单一原则是设计模式中非常重要的思想。如果,你能够在一个类中找到多于一个的功能,那么,这个类就该进行抽象和拆分了。在OOP中有一个大忌讳,就是万能类。一个成千上万行的类,臃肿而庞大,为什么不柴分成多个类呢?每个类负责一个功能,各思其职。

策略模式,策略就是算法和变化,策略模式就是对算法和变化的封装。是条件选择从客户端到服务端的转移。客户端与算法类的彻底隔离。

<?php
abstract class Strategy{
    public $paramA = '';
    public $paramB = '';
    public function getResult(){

    }
}
class AlgorithmA extends Strategy{
    public function algorithmA(){
        //算法A的实现
    }
}
class AlgorithmB extends Strategy{
    public function algorithmB(){
        //算法B的实现
    }
}
class AlgorithmC extends Strategy{
    public function algorithmC(){
        //算法C的实现
    }
}
?>

场景: 沃尔玛要做一个收银软件。有打8折,打5折等,有每满100减20等。

<?php
//抽象类
abstract class Pay{
    public $cash = '';
    public $total = '';
    public function getResult(){
        return $this->total;
    }
}
//打折
class Discount extends Pay{
    public function algorithm($cash, $discount=0.8){
        $this->total = $cash * $discount;
        return $this->getResult();
    }
}
//满多少减多少
class Reduce extends Pay{
    public function algorithm($cash, $satisfied=100, $returnCash=20){
        $this->total = $cash - floor($cash / $satisfied) * $returnCash;
        return $this->getResult();
    }
}
class Context{
    private $obj;
    public function __construct($type){
        switch($type){
            case 1:
                $this->obj = new Discount();
                break;
            case 2:
                $this->obj = new Reduce();
                break;
        }
    }
    public function algorithm(){
        $this->obj->algorithm();
    }
}
//客户端
$obj = new Context($_GET['type']);
echo $obj->algorithm();
?>

优点:客户端不需要做条件判断,而且仅仅需要认识一个类即可。乍一看和简单工厂很相似呢。