标签 设计模式 下的文章

工厂方法:定义一个工厂接口,用来创建产品对象,将实际创建工作推迟到子类当中。
工厂方法来源于简单工厂模式,是简单工厂模式的一个衍生品。核心的工厂类不再进行类的实例化,核心工厂类不再负责产品的创建,核心的工厂类只负责子类的接口,使核心工厂类抽象化,成为一个抽象工厂。
工厂方法的优点:在简单工厂模式的基础上再次对核心工厂类进行抽象,在需要添加新的产品时,更好的依赖于开放-封闭原则,不需要修改具体的工厂角色即可扩展。
场景:简单计算器。以PHP为代码实现环境。
简单工厂模式:

<?php
class Calculator{
    public $numberA;
    public $numberB;
    public $result;
    public function returnResult(){

    }
}
class Add extends Calculator{
    public function __construct($a, $b){
        $this->numberA = $a;
        $this->numberB = $b;
    }
    public function returnResult(){
        $this->result = $this->numberA + $this->numberB;
        return $this->returnResult();
    }
}
class Sub extends Calculator{
    public function __construct($a, $b){
        $this->numberA = $a;
        $this->numberB = $b;
    }
    public function returnResult(){
        $this->result = $this->numberA - $this->numberB;
        return $this->returnResult();
    }
}
class Factory{
    public function calculatorFactory($operator, $numberA, $numberB){
        $obj = '';
        switch($operator){
            case '+':
                $obj = new Add($numberA, $numberB);
                break;
            case '-':
                $obj = new Sub($numberA, $numberB);
                break;
        }
        $result = $obj->returnResult();
        return $result;
    }
}
//客户端/接口
$operation = isset($_GET['operation']) ? $_GET['operation'] : '+';
$numberA = $_GET['numberA'];
$numberB = $_GET['numberB'];
$obj = new Factory();
echo $obj->calculatorFactory($operation, $numberA, $numberB);
?>

工厂方法:

<?php
class Calculator{
    public $numberA;
    public $numberB;
    public $result;
    public function returnResult(){}
}
class Add extends Calculator{
    public function __construct($a, $b){
        $this->numberA = $a;
        $this->numberB = $b;
    }
    public function returnResult(){
        $this->result = $this->numberA + $this->numberB;
        return $this->returnResult();
    }
}
class Sub extends Calculator{
    public function __construct($a, $b){
        $this->numberA = $a;
        $this->numberB = $b;
    }
    public function returnResult(){
        $this->result = $this->numberA - $this->numberB;
        return $this->returnResult();
    }
}
class Factory extends Calculator{
    public static function create($class, $numberA, $numberb){
        return new $class($numberA, $numberb);
    }
}
//客户端/接口
$operator = isset($_GET['operation']) ? $_GET['operation'] : '+';
$numberA = $_GET['numberA'];
$numberB = $_GET['numberB'];
switch($operator){
    case '+':
        $class = 'objAdd';
        break;
    case '-':
        $class = 'objSub';
        break;
}
$obj = Factory::create($class, $numberA, $numberb);
echo $obj->returnResult();
?>

简单工厂模式VS工厂方法模式:
简单工厂的选择在工厂类,

代理模式,是为其他对象提供一种代理以控制对这个对象的访问,代理模式是设计模式的一种。应用较为广泛,是一个对象需要访问另一个对象,出于某种原因或目的,在两个对象之间添加了一个中间对象。A对象访问B对象的方法,B对象的该方法实际是调用的C对象的方法,间接的完成了A对象对C对象的访问。这种模式叫做代理模式。
以PHP为代码环境,实现设计模式中的代理模式。

<?php
abstract class Subject(){
abstract class Subject(){
    public function actionA();
	public function actionB(){;
    public function actionC();
}
class Substance implements Subject(){
    public function actionA(){
        echo '方法A的实现';	
	}
	public function actionB(){
        echo '方法B的实现';
	}
    public function actionC(){
	    echo '方法C的实现';
    } 
}
class Proxy implements Subject(){
    $protected $obj;
	public function __construct(){
        $obj = new Substance();
    }
    public function actionA(){
        $this->obj->actionA;
    }
    public function actionB(){
        $this->obj->actionB;
    }
    public function actionC(){
	    $this->obj->actionC;
    } 
}
//客户端/接口
$obj = new Proxy();
$obj->actionA();
$obj->actionB();
$obj->actionC();	
}
?>

代理模式的使用场景:(整理自大话设计模式一书)
第一、远程代理,为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。
第二、虚拟代理,是根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的对象。
第三、安全代理,用来控制真实对象的访问权限。
第四、智能指引,是指当调用真实对象时,代理处理另外一些事情。(我的理解是,比如底层有一个封装好的Mysql类,在上层应用层读取数据库时,先经过一个代理类,可以检查数据完整性,参数合法性,计数器等等,然后由代理类调用真实的Mysql类)

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

<?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和主板的指令集,将内存条根据针脚插入主板中,就可以工作,因为它依靠针脚(接口)来传输数据。各个硬件之间相互独立。对某个硬件而言,对内我的指令集和工作方式是封闭的,你不可以修改也不需要知道,对外,我有接口,支持扩展,大家可以把我插了就用。这就是开放-封闭原则的体现。是高聚能低耦合的典型例子。