lane 发布的文章

模板方法模式,是最为常见,也是使用最为广泛的一种设计模式,很多程序猿都不知道,自己随便写的代码,也是一种设计模式。如果只能学习一种设计模式的话,那么就应该学习模板模式。
模板模式:在一个方法里定义算法的骨架,将一些步骤延迟到其子类。顾名思义,模板模式,就是有一个固定的,现成的模板,往里面套东西呗。比如PPT,WORD,EXCEL等,Microsoft为我们提供了大量的模板。可以直接套用,也可以略做修改。总之,比我们自己全新做要省很多事儿。
抽出多个类的共同特性,成为一个父类,父类根据需求封装好一个算法骨架,然后子类调用父类即可。
以PHP为代码环境,

<?php
class TestPaper{
    public $name;
    public $classes;
    public function __construct($name, $classes){
        $this->name = $name;
        $this->classes = $classes;
    }
    public function display(){
        echo '姓名:' . $this->name . ', 班级:' . $this->classes;
        $this->separate();
    }
    public function title1($answer){
        echo '题目一:******';
        echo '答案:' . $this->answer($answer);
        $this->separate();
    }
    public function title2($answer){
        echo '题目二:******';
        echo '答案:' . $this->answer($answer);
        $this->separate();
    }
    public function answer($answer){
        return $answer;
    }
    public function separate(){
        echo '<br>';
    }
}
class studentA extends TestPaper{
    public function __construct($name, $classes){
        parent::__construct($name, $classes);
    }
    public function answerTestPaper(){
        $this->display();
        $this->title1('C');
        $this->title1('B');
    }
}
class studentB extends TestPaper{
    public function __construct($name, $classes){
        parent::__construct($name, $classes);
    }
    public function answerTestPaper(){
        $this->display();
        $this->title1('A');
        $this->title1('D');
    }
}
$studentA = new studentA('小明', '一');
$studentA->answerTestPaper();
$studentB = new studentB('小红', '二');
$studentB->answerTestPaper();
?>

原型模式提取重复功能,避免了程序员喜欢复制粘贴的坏习惯。设计模式中的原型模式就是,用原型实例指定创建对象的重力,通过拷贝这些原型来创建新的对象从一个对象再创建另外一个可定制的对象,而且不需要知道创建的任何细节。
浅复制 VS 深复制:
浅复制是对数字,字符串等类型进行传值复制,而对对象来讲是引用复制,即只是对内存地址进行赋值而不是新建一个对象的变量。在浅复制中,对一个对象的属性改变,另一个对象的该属性也会被改变,类比于C语言的指针,PHP在调用方法时&$var的传递。
以PHP为代码环境。

<?php
//家庭类
class Home{
    public $money;
    public function __construct($money){
        $this->money = $money;
	}
}
//家庭成员类
class member{
    public $id;
    public $name;
    public $obj;
    public function __construct($id, $name, Home $obj){
        $this->setId($id);
        $this->setName($name);
		$this->obj = $obj;
    }
    public function setId($id){
        $this->id = $id;
    }
	public function setName($name){
        $this->name = $name;
    }
    public function display(){
	    echo 'ID为' . $this->id . ',名称为' . $this->name . ',资产为' . $this->obj->money . '<br>';
    }
	public function __clone(){
        //深度复制(克隆),因为克隆只能克隆数字,字符串等,对对象变量是引用传值。	
        $this->obj = clone $this->obj;
    }
}
//客户端/接口
$obj1 = new member(1, '小轩', new Home('10000'));
$obj1->display();
$obj2 = clone $obj1;
$obj2->setId(2);
$obj2->setName('小玮');
$obj2->obj->money = 2000;
$obj2->display();
//根据这句输出可以看到,对象1和对象2值是不一样的,删掉上面的注释部分再看,又是一样的了,这就是深复制和浅复制。
$obj1->display();
?>

工厂方法:定义一个工厂接口,用来创建产品对象,将实际创建工作推迟到子类当中。
工厂方法来源于简单工厂模式,是简单工厂模式的一个衍生品。核心的工厂类不再进行类的实例化,核心工厂类不再负责产品的创建,核心的工厂类只负责子类的接口,使核心工厂类抽象化,成为一个抽象工厂。
工厂方法的优点:在简单工厂模式的基础上再次对核心工厂类进行抽象,在需要添加新的产品时,更好的依赖于开放-封闭原则,不需要修改具体的工厂角色即可扩展。
场景:简单计算器。以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个类彼此独立,如果使用,在客户端进行不同的组合。