设计模式详解及PHP实现

由于工作中需要写一个比较复杂的类库,这个类库需要很高的扩展性、维护性及复用性。为了麻烦现在简单未来,使用设计模式思想来优化类库可以使工作事半功倍,在这里记录一下各种设计模式,总结一下知识,顺便也可以做为自己日后的参考。

设计模式(Design Patterns)

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 –百度百科

In software engineering, a design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. –Wikipedia

在软件开发过程中,一个功能的实现方式多种多样,不同方法的可扩展性、可维护性以及复用性都是不一样的。随着一个人对自己项目代码的要求增加,他会逐渐思考和实践出自己的一套方法或者思想,这种方法或思想决定了他设计出的架构或者编写出的代码的质量优劣。设计模式就属于这样一种经验的积累,是由大量优秀的工程师或者架构师总结和提炼的精华,学习好设计模式等于让我们站在了巨人的肩膀上,从一个高的起点出发,可以避免走很多弯路。

设计模式的使用一定是根据场景来选择的,而且设计模式的实现方式也不是固定的,我们一定要在理解现有设计模式的基础上,根据自己实际的情况不断实践不断理解。就像所谓的《泡妞大全》,读千万遍都不如实践一次来的实际。

如果你对设计模式完全没有感觉,那么去好好写一个类库,或者一个简单的MVC框架,这个过程会让你感觉到自己缺失的部分。

分类

在《设计模式:可复用面向对象软件的基础》(Design Patterns: Elements of Reusable Object-Oriented Software) 这本书中,作者把设计模式分了三大类:

创建型模式(Creational patterns)

创建型模式是为了解决创建对象时候遇到的问题。因为基本的对象创建方式可能会导致设计上的问题,或增加设计的复杂度。创建型模式有两个主导思想:一是将系统使用的具体类封装起来,二是隐藏这些具体类的实例创建和结合方式。

最常见的五种创建型模式如下:

结构型模式(Structural pattern)

结构型模式是通过定义一个简单的方法来实现和了解实体间关系,从而简化设计。

行为型模式(Behavioral pattern)

行为型模式用来识别对象之间的常用交流模式并加以实现,使得交流变得更加灵活。

关系

这里有一张各个模式关系图,可以在了解各个模式以后梳理一下

设计模式

参考

  1. Wikipedia: Software design pattern
  2. 百度百科:设计模式

建造者模式(Builder pattern)

建造者模式是一种创建型模式,它可以让一个产品的内部表象和和产品的生产过程分离开,从而可以生成具有不同内部表象的产品。

Builder模式中主要角色

适用性

类图

builder pattern

实例

<?php

class Product { // 产品本身
    private $_parts;
    public function __construct() { $this->_parts = array(); }
    public function add($part) { return array_push($this->_parts, $part); }
}

abstract class Builder { // 建造者抽象类
    public abstract function buildPart1();
    public abstract function buildPart2();
    public abstract function getResult();
}

class ConcreteBuilder extends Builder { // 具体建造者
    private $_product;
    public function __construct() { $this->_product = new Product(); }
    public function buildPart1() { $this->_product->add("Part1"); }
    public function buildPart2() { $this->_product->add("Part2"); }
    public function getResult() { return $this->_product; }
}

class Director {
    public function __construct(Builder $builder) {
        $builder->buildPart1();
        $builder->buildPart2();
    }
}

// client
$buidler = new ConcreteBuilder();
$director = new Director($buidler);
$product = $buidler->getResult();
?>

优缺点

优点

建造者模式可以很好的将一个对象的实现与相关的“业务”逻辑分离开来,从而可以在不改变事件逻辑的前提下,使增加(或改变)实现变得非常容易。

缺点

建造者接口的修改会导致所有执行类的修改。

参考

  1. Wikipedia: Bulider pattern
  2. Wikipedia: 生成器模式
  3. PHP设计模式笔记:使用PHP实现建造者模式

单例模式(Singleton pattern)

抽象工厂模式是一种创建型模式,在应用这个模式时,单例对象的类必须保证只有一个实例存在。

实现单例模式的思路是:一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。

单例模式中主要角色

Singleton定义一个getInstance操作,允许客户访问它唯一的实例。

这个例子也简单,就像我有6个老婆(快醒醒!),她们在喊”老公”的时候都是指我。不管什么时候,喊老公擦地,做饭,洗衣服都是指同一个人,PHP不编写多线程,所以不存在抢占问题,如果换别的语言编写,一定得考虑到抢占问题!老公是不可以边擦地边做饭的!

适用性

类图

singleton pattern

实例

<?php
public class Singleton {
    private static $_instance = NULL;

    // 私有构造方法
    private function __construct() {}

    public static function getInstance() {
        if (is_null(self::$_instance)) {
            self::$_instance = new Singleton();
        }
        return self::$_instance;
    }

    // 防止克隆实例
    public function __clone(){
        die('Clone is not allowed.' . E_USER_ERROR);
    }
}
?>

在此实例中,Singleton禁止了克隆及外部初始化,使得此类只可以通过getInstance()方法来获得实例,而这个实例只会在第一次使用时创建,以后每次都获得同一实例。

优缺点

优点

缺点

单例模式在多线程的应用场合下必须小心使用。如果当唯一实例尚未创建时,有两个线程同时调用创建方法,那么它们同时没有检测到唯一实例的存在,从而同时各自创建了一个实例,这样就有两个实例被构造出来,从而违反了单例模式中实例唯一的原则。解决这个问题的办法是为指示类是否已经实例化的变量提供一个互斥锁(虽然这样会降低效率)。

参考

  1. Wikipedia: 单例模式
  2. Wikipedia: Singleton pattern
  3. PHP设计模式笔记:使用PHP实现单例模式

适配器模式(Adapter pattern)

适配器模式是一种结构型模式,它将一个类的接口转接成用户所期待的。一个适配使得因接口不兼容而不能在一起工作的类工作在一起,做法是将类别自己的接口包裹在一个已存在的类中。

适配器模式中主要角色

适用性

1、你想使用一个已经存在的类,而它的接口不符合你的需求 2、你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作 3、你想使用一个已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口(仅限于对象适配器)

类适配器模式与对象适配器

类适配器:Adapter与Adaptee是继承关系

对象适配器:Adapter与Adaptee是委托关系

类图

类适配器

class adapter pattern

对象适配器

object adapter pattern

实例

类适配器

<?php

interface Target {
    public function sampleMethod1();
    public function sampleMethod2();
}

class Adaptee { // 源角色
    public function sampleMethod1() {}
}

class Adapter extends Adaptee implements Target { // 适配后角色
    public function sampleMethod2() {}
}

// client
$adapter = new Adapter();
$adapter->sampleMethod1();
$adapter->sampleMethod2();

?>

对象适配器

<?php

interface Target {
    public function sampleMethod1();
    public function sampleMethod2();
}

class Adaptee {
    public function sampleMethod1() {}
}

class Adapter implements Target {
    private $_adaptee;
    public function __construct(Adaptee $adaptee) {
        $this->_adaptee = $adaptee;
    }

    public function sampleMethod1() { $this->_adaptee->sampleMethod1(); }

    public function sampleMethod2() {}
}

$adaptee = new Adaptee();
$adapter = new Adapter($adaptee);
$adapter->sampleMethod1();
$adapter->sampleMethod2();
?>

参考

  1. Wikipedia: Adapter pattern
  2. Wikipedia: 适配器模式
  3. PHP设计模式笔记:使用PHP实现适配器模式

桥接模式(Bridge pattern)

桥接模式是一种结构型模式,它是软件设计模式中最复杂的模式之一,它把事物对象和其具体行为、具体特征分离开来,使它们可以各自独立的变化。事物对象仅是一个抽象的概念。如“圆形”、“三角形”归于抽象的“形状”之下,而“画圆”、“画三角”归于实现行为的“画图”类之下,然后由“形状”调用“画图”。

主要角色

适用性

类图

bridge pattern

实例

<?php
abstract class Abstraction { // 抽象化角色,抽象化给出的定义,并保存一个对实现化对象的引用。
    protected $imp; // 对实现化对象的引用
    public function operation() {
        $this->imp->operationImp();
    }
}

class RefinedAbstraction extends Abstraction { // 修正抽象化角色, 扩展抽象化角色,改变和修正父类对抽象化的定义。
     public function __construct(Implementor $imp) {
        $this->imp = $imp;
    }
    public function operation() { $this->imp->operationImp(); }
}

abstract class Implementor { // 实现化角色, 给出实现化角色的接口,但不给出具体的实现。
    abstract public function operationImp();
}

class ConcreteImplementorA extends Implementor { // 具体化角色A
    public function operationImp() {}
}

class ConcreteImplementorB extends Implementor { // 具体化角色B
    public function operationImp() {}
}

// client
$abstraction = new RefinedAbstraction(new ConcreteImplementorA());
$abstraction->operation();

$abstraction = new RefinedAbstraction(new ConcreteImplementorB());
$abstraction->operation();
?>

优点

参考

  1. Wikipedia: Bridge pattern
  2. Wikipedia: 桥接模式
  3. PHP设计模式笔记:使用PHP实现桥接模式

合成模式(Composite pattern)

合成模式是一种结构型模式,它将对象组合成树形结构以表示”部分-整体”的层次结构。Composite使用户对单个对象和组合对象的使用具有一致性。 Composite变化的是一个对象的结构和组成。

主要角色

适用性

类图

安全式合成模式

safe composite pattern

透明式合成模式

transparent composite pattern

实例

安全式合成模式

在Composite类里面声明所有的用来管理子类对象的方法。这样的做法是安全的。因为树叶类型的对象根本就没有管理子类的方法,因此,如果客户端对树叶类对象使用这些方法时,程序会在编译时期出错。编译通不过,就不会出现运行时期错误。这样的缺点是不够透明,因为树叶类和合成类将具有不同的接口。

<?php
interface Component {
    public function getComposite(); //返回自己的实例
    public function operation();
}

class Composite implements Component { // 树枝组件角色
    private $_composites;
    public function __construct() { $this->_composites = array(); }
    public function getComposite() { return $this; }
     public function operation() {
         foreach ($this->_composites as $composite) {
            $composite->operation();
        }
     }

    public function add(Component $component) {  //聚集管理方法 添加一个子对象
        $this->_composites[] = $component;
    }

    public function remove(Component $component) { // 聚集管理方法 删除一个子对象
        foreach ($this->_composites as $key => $row) {
            if ($component == $row) { unset($this->_composites[$key]); return TRUE; }
        }
        return FALSE;
    }

    public function getChild() { // 聚集管理方法 返回所有的子对象
       return $this->_composites;
    }

}

class Leaf implements Component {
    private $_name;
    public function __construct($name) { $this->_name = $name; }
    public function operation() {}
    public function getComposite() {return null;}
}

// client
$leaf1 = new Leaf('first');
$leaf2 = new Leaf('second');

$composite = new Composite();
$composite->add($leaf1);
$composite->add($leaf2);
$composite->operation();

$composite->remove($leaf2);
$composite->operation();
?>

透明式合成模式

在Composite类里面声明所有的用来管理子类对象的方法。这样做的是好处是所有的组件类都有相同的接口。在客户端看来,树叶类和合成类对象的区别起码在接口层次上消失了,客户端可以同等的对待所有的对象。这就是透明形式的合成模式,缺点就是不够安全,因为树叶类对象和合成类对象在本质上是有区别的。树叶类对象不可能有下一个层次的对象,因此调用其添加或删除方法就没有意义了,这在编译期间是不会出错的,而只会在运行时期才会出错。

<?php
interface Component { // 抽象组件角色
    public function getComposite(); // 返回自己的实例
    public function operation(); // 示例方法
    public function add(Component $component); // 聚集管理方法,添加一个子对象
    public function remove(Component $component); // 聚集管理方法 删除一个子对象
    public function getChild(); // 聚集管理方法 返回所有的子对象
}

class Composite implements Component { // 树枝组件角色
    private $_composites;
    public function __construct() { $this->_composites = array(); }
    public function getComposite() { return $this; }
    public function operation() { // 示例方法,调用各个子对象的operation方法
        foreach ($this->_composites as $composite) {
            $composite->operation();
        }
    }
    public function add(Component $component) { // 聚集管理方法 添加一个子对象
        $this->_composites[] = $component;
    }
    public function remove(Component $component) { // 聚集管理方法 删除一个子对象
        foreach ($this->_composites as $key => $row) {
            if ($component == $row) { unset($this->_composites[$key]); return TRUE; }
        }
        return FALSE;
    }
    public function getChild() { // 聚集管理方法 返回所有的子对象
       return $this->_composites;
    }

}

class Leaf implements Component {
    private $_name;
    public function __construct($name) {$this->_name = $name;}
    public function operation() {}
    public function getComposite() { return null; }
    public function add(Component $component) { return FALSE; }
    public function remove(Component $component) { return FALSE; }
    public function getChild() { return null; }
}

// client
$leaf1 = new Leaf('first');
$leaf2 = new Leaf('second');

$composite = new Composite();
$composite->add($leaf1);
$composite->add($leaf2);
$composite->operation();

$composite->remove($leaf2);
$composite->operation();
?>

优缺点

优点

缺点

参考

  1. Wikipedia: Composite pattern
  2. PHP设计模式笔记:使用PHP实现合成模式

装饰器模式(Decorator pattern)

装饰器模式是一种结构型模式,它动态的给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活【GOF95】 装饰模式是以对客户透明的方式动态地给一个对象附加上更多的职责。这也就是说,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。

主要角色

适用性

类图

decorator pattern

实例

<?php
interface Component {
    public function operation();
}

abstract class Decorator implements Component{ // 装饰角色
    protected  $_component;
    public function __construct(Component $component) {
        $this->_component = $component;
    }
    public function operation() {
        $this->_component->operation();
    }
}

class ConcreteDecoratorA extends Decorator { // 具体装饰类A
    public function __construct(Component $component) {
        parent::__construct($component);
    }
    public function operation() {
        parent::operation();    //  调用装饰类的操作
        $this->addedOperationA();   //  新增加的操作
    }
    public function addedOperationA() {}
}

class ConcreteDecoratorB extends Decorator { // 具体装饰类B
    public function __construct(Component $component) {
        parent::__construct($component);
    }
    public function operation() {
        parent::operation();
        $this->addedOperationB();
    }
    public function addedOperationB() {}
}

class ConcreteComponent implements Component{
    public function operation() {}
}

// clients
$component = new ConcreteComponent();
$decoratorA = new ConcreteDecoratorA($component);
$decoratorB = new ConcreteDecoratorB($decoratorA);

$decoratorA->operation();
$decoratorB->operation();
?>

优缺点

优点

缺点

参考

  1. Wikipedia: Decorator pattern
  2. Wikipedia: 修饰模式
  3. PHP设计模式笔记:使用PHP实现装饰模式

门面模式(Facade pattern)

门面模式是一种结构型模式,它为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层次的接口,使得子系统更加容易使用。

主要角色

门面(Facade)角色

子系统(subsystem)角色

适用性

类图

facade pattern

实例

<?php
class Camera {
    public function turnOn() {}
    public function turnOff() {}
    public function rotate($degrees) {}
}

class Light {
    public function turnOn() {}
    public function turnOff() {}
    public function changeBulb() {}
}

class Sensor {
    public function activate() {}
    public function deactivate() {}
    public function trigger() {}
}

class Alarm {
    public function activate() {}
    public function deactivate() {}
    public function ring() {}
    public function stopRing() {}
}

class SecurityFacade {
    private $_camera1, $_camera2;
    private $_light1, $_light2, $_light3;
    private $_sensor;
    private $_alarm;

    public function __construct() {
        $this->_camera1 = new Camera();
        $this->_camera2 = new Camera();

        $this->_light1 = new Light();
        $this->_light2 = new Light();
        $this->_light3 = new Light();

        $this->_sensor = new Sensor();
        $this->_alarm = new Alarm();
    }

    public function activate() {
        $this->_camera1->turnOn();
        $this->_camera2->turnOn();

        $this->_light1->turnOn();
        $this->_light2->turnOn();
        $this->_light3->turnOn();

        $this->_sensor->activate();
        $this->_alarm->activate();
    }

    public  function deactivate() {
        $this->_camera1->turnOff();
        $this->_camera2->turnOff();

        $this->_light1->turnOff();
        $this->_light2->turnOff();
        $this->_light3->turnOff();

        $this->_sensor->deactivate();
        $this->_alarm->deactivate();
    }
}


//client
$security = new SecurityFacade();
$security->activate();
?>

优缺点

优点

参考

  1. Wikipedia: Facade pattern
  2. Wikipedia: 外观模式
  3. PHP设计模式笔记:使用PHP实现门面模式

享元模式(Flyweight Pattern)

享元模式是一种结构型模式,它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。

主要角色

适用性

类图

flyweight pattern

实例

<?php
abstract class Flyweight { // 抽象享元角色
    abstract public function operation($state);
}

class ConcreteFlyweight extends Flyweight { // 具体享元角色
    private $_intrinsicState = null;
    public function __construct($state) {
        $this->_intrinsicState = $state;
    }
    public function operation($state) {}
}

class UnsharedConcreteFlyweight extends Flyweight { // 不共享的具体享元,客户端直接调用
    private $_intrinsicState = null;
    public function __construct($state) {
        $this->_intrinsicState = $state;
    }
    public function operation($state) {}
}

class FlyweightFactory { // 享元工厂角色
    private $_flyweights;
    public function __construct() {
        $this->_flyweights = array();
    }
    public function getFlyweigth($state) {
        if (isset($this->_flyweights[$state])) {
            return $this->_flyweights[$state];
        } else {
            return $this->_flyweights[$state] = new ConcreteFlyweight($state);
        }
    }
}

// client
$flyweightFactory = new FlyweightFactory();
$flyweight = $flyweightFactory->getFlyweigth('state A');
$flyweight->operation('other state A');

$flyweight = $flyweightFactory->getFlyweigth('state B');
$flyweight->operation('other state B');

// 不共享的对象,单独调用
$uflyweight = new UnsharedConcreteFlyweight('state A');
$uflyweight->operation('other state A');
?>

优缺点

优点

缺点

参考

  1. Wikipedia: Flyweight pattern
  2. Wikipedia: 享元模式
  3. PHP设计模式笔记:使用PHP实现享元模式

观察者模式(Observer pattern)

观察者模式是一种行为型模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

又称为发布-订阅(Publish-Subscribe)模式、模型-视图(Model-View)模式、源-监听(Source-Listener)模式、或从属者(Dependents)模式

主要角色

适用性

类图

observer pattern

实例

<?php
interface Subject { // 抽象主题角色
    public function attach(Observer $observer); // 增加一个新的观察者对象
    public function detach(Observer $observer); // 删除一个已注册过的观察者对象
    public function notifyObservers(); // 通知所有注册过的观察者对象
}

class ConcreteSubject implements Subject { // 具体主题角色
    private $_observers;
    public function __construct() { $this->_observers = array(); }
    public function attach(Observer $observer) {
        return array_push($this->_observers, $observer);
    }
    public function detach(Observer $observer) {
        $index = array_search($observer, $this->_observers);
        if ($index === FALSE || ! array_key_exists($index, $this->_observers)) {
            return FALSE;
        }
        unset($this->_observers[$index]);
        return TRUE;
    }
    public function notifyObservers() {
        if (!is_array($this->_observers)) { return FALSE; }
        foreach ($this->_observers as $observer) {
            $observer->update();
        }
        return TRUE;
    }

}

interface Observer { // 抽象观察者角色
    public function update(); // 更新方法
}

class ConcreteObserver implements Observer {
    private $_name;
    public function __construct($name) { $this->_name = $name; }
    public function update() {}
}

$subject = new ConcreteSubject();

/* 添加第一个观察者 */
$observer1 = new ConcreteObserver('Mac');
$subject->attach($observer1);
$subject->notifyObservers(); // 主题变化,通知观察者

/* 添加第二个观察者 */
$observer2 = new ConcreteObserver('Win');
$subject->attach($observer2);
$subject->notifyObservers();

$subject->detach($observer1);
$subject->notifyObservers();
?>

优缺点

优点

缺点

参考

  1. Wikipedia: Observer pattern
  2. Wikipedia: 观察者模式
  3. PHP设计模式笔记:使用PHP实现观察者模式

原型模式(Prototype pattern)

原型模式是一种创建者模式,其特点在于通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。

原型模式中主要角色

适用性

类图

prototype pattern

实例

<?php

interface Prototype { public function copy(); }

class ConcretePrototype implements Prototype{
    private  $_name;
    public function __construct($name) { $this->_name = $name; }
    public function copy() { return clone $this;}
}

class Demo {}

// client

$demo = new Demo();
$object1 = new ConcretePrototype($demo);
$object2 = $object1->copy();
?>

优缺点

优点

缺点

Prototype模式的最主要缺点就是每一个类必须配备一个克隆方法。而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事。

参考

  1. Wikipedia: Prototype pattern
  2. Wikipedia: 原型模式
  3. PHP设计模式笔记:使用PHP实现原型模式

代理模式(Proxy pattern)

代理模式是一种结构型模式,它可以为其他对象提供一种代理以控制对这个对象的访问。

主要角色

适用性

类图

proxy pattern

实例

<?php
abstract class Subject { // 抽象主题角色
    abstract public function action();
}

class RealSubject extends Subject { // 真实主题角色
    public function __construct() {}
    public function action() {}
}

class ProxySubject extends Subject { // 代理主题角色
    private $_real_subject = NULL;
    public function __construct() {}

    public function action() {
        $this->_beforeAction();
        if (is_null($this->_real_subject)) {
            $this->_real_subject = new RealSubject();
        }
        $this->_real_subject->action();
        $this->_afterAction();
    }
    private function _beforeAction() {}
    private function _afterAction() {}
}

// client
$subject = new ProxySubject();
$subject->action();
?>

参考

  1. Wikipedia: Proxy pattern
  2. Wikipedia: 代理模式
  3. 代理模式(Proxy)和PHP的反射功能

策略模式(Strategy pattern)

策略模式是一种行为型模式,它定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。策略模式可以使算法可独立于使用它的客户而变化。

主要角色

适用性

类图

strategy pattern

实例

<?php
interface Strategy { // 抽象策略角色,以接口实现
    public function algorithmInterface(); // 算法接口
}

class ConcreteStrategyA implements Strategy { // 具体策略角色A
    public function algorithmInterface() {}
}

class ConcreteStrategyB implements Strategy { // 具体策略角色B
    public function algorithmInterface() {}
}

class ConcreteStrategyC implements Strategy { // 具体策略角色C
    public function algorithmInterface() {}
}

class Context { // 环境角色
    private $_strategy;
    public function __construct(Strategy $strategy) {
        $this->_strategy = $strategy;
    }
    public function contextInterface() {
        $this->_strategy->algorithmInterface();
    }
}

// client
$strategyA = new ConcreteStrategyA();
$context = new Context($strategyA);
$context->contextInterface();

$strategyB = new ConcreteStrategyB();
$context = new Context($strategyB);
$context->contextInterface();

$strategyC = new ConcreteStrategyC();
$context = new Context($strategyC);
$context->contextInterface();
?>

优缺点

优点

缺点

参考

  1. Wikipedia: Strategy pattern
  2. Wikipedia: 策略模式
  3. PHP设计模式笔记:使用PHP实现策略模式

命令模式(Command pattern)

命令模式是一种行为型模式,它将一个请求封装为一个对象,从而使用你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。

请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。

主要角色

适用性

类图

command pattern

实例

<?php
interface Command { // 命令角色
    public function execute(); // 执行方法
}

class ConcreteCommand implements Command { // 具体命令方法
    private $_receiver;
    public function __construct(Receiver $receiver) {
        $this->_receiver = $receiver;
    }
    public function execute() {
        $this->_receiver->action();
    }
}

class Receiver { // 接收者角色
    private $_name;
    public function __construct($name) {
        $this->_name = $name;
    }
    public function action() { }
}

class Invoker { // 请求者角色
    private $_command;
    public function __construct(Command $command) {
        $this->_command = $command;
    }
    public function action() {
        $this->_command->execute();
    }
}

$receiver = new Receiver('hello world');
$command = new ConcreteCommand($receiver);
$invoker = new Invoker($command);
$invoker->action();
?>

优缺点

优点

缺点

参考

  1. Wikipedia: Command pattern
  2. Wikipedia: 命令模式
  3. PHP设计模式笔记:使用PHP实现命令模式

解释器模式(Interpreter pattern)

解释器模式是一种行为型模式,它给定一个语言, 定义它的文法的一种表示,并定义一个解释器, 该解释器使用该表示来解释语言中的句子。

类图

interpreter pattern

实例

<?php
class Expression {
    function interpreter($str) {
        return $str;
    }
}

class ExpressionNum extends Expression {
    function interpreter($str) {
        switch($str) {
            case "0": return "零";
            case "1": return "一";
            case "2": return "二";
            case "3": return "三";
            case "4": return "四";
            case "5": return "五";
            case "6": return "六";
            case "7": return "七";
            case "8": return "八";
            case "9": return "九";
        }
    }
}

class ExpressionCharater extends Expression {
    function interpreter($str) {
        return strtoupper($str);
    }
}

class Interpreter {
    function execute($string) {
        $expression = null;
        for($i = 0;$i<strlen($string);$i++) {
            $temp = $string[$i];
            switch(true) {
                case is_numeric($temp): $expression = new ExpressionNum(); break;
                default: $expression = new ExpressionCharater();
            }
            echo $expression->interpreter($temp);
        }
    }
}

//client
$obj = new Interpreter();
$obj->execute("12345abc");
?>

参考

  1. Wikipedia: Strategy pattern
  2. php设计模式 Interpreter(解释器模式)

迭代器模式(Iterator pattern)

迭代器模式是一种行为型模式,它是一种最简单也最常见的设计模式。它可以让使用者透过特定的接口巡访容器中的每一个元素而不用了解底层的实作。

适用性

实例

<?php
class sample implements Iterator {
    private $_items ;

    public function __construct(&$data) {
        $this->_items = $data;
    }
    public function current() {
        return current($this->_items);
    }

    public function next() {
        next($this->_items);
    }

    public function key() {
        return key($this->_items);
    }

    public function rewind() {
        reset($this->_items);
    }

    public function valid() {
        return ($this->current() !== FALSE);
    }
}

// client
$data = array(1, 2, 3, 4, 5);
$sa = new sample($data);
foreach ($sa AS $key => $row) {
    echo $key, ' ', $row, '<br />';
}
?>

参考

  1. Wikipedia: Iterator pattern
  2. PHP中迭代器的简单实现及Yii框架中的迭代器实现

中介者模式(Mediator pattern)

中介者模式是一种行为型模式,它包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用,从而使它们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可以彼此独立的变化。

主要角色

实例

<?php
abstract class Mediator { // 中介者角色
    abstract public function send($message,$colleague);
}

abstract class Colleague { // 抽象对象
    private $_mediator = null;
    public function __construct($mediator) {
        $this->_mediator = $mediator;
    }
    public function send($message) {
        $this->_mediator->send($message,$this);
    }
    abstract public function notify($message);
}

class ConcreteMediator extends Mediator { // 具体中介者角色
    private $_colleague1 = null;
    private $_colleague2 = null;
    public function send($message,$colleague) {
        if($colleague == $this->_colleague1) {
            $this->_colleague1->notify($message);
        } else {
            $this->_colleague2->notify($message);
        }
    }
    public function set($colleague1,$colleague2) {
        $this->_colleague1 = $colleague1;
        $this->_colleague2 = $colleague2;
    }
}

class Colleague1 extends Colleague { // 具体对象角色
    public function notify($message) { }
}

class Colleague2 extends Colleague { // 具体对象角色
    public function notify($message) { }
}

// client
$objMediator = new ConcreteMediator();
$objC1 = new Colleague1($objMediator);
$objC2 = new Colleague2($objMediator);
$objMediator->set($objC1,$objC2);
$objC1->send("to c2 from c1");
$objC2->send("to c1 from c2");
?>

参考

  1. Wikipedia: Mediator pattern

备忘录模式(Memento pattern)

备忘录模式是一种行为型模式,它在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样可以在以后把该对象的状态恢复到之前保存的状态。

主要角色

适用性

类图

memento pattern

实例

<?php
class Originator { // 发起人(Originator)角色
    private $_state;
    public function __construct() {
        $this->_state = '';
    }
    public function createMemento() { // 创建备忘录
        return new Memento($this->_state);
    }
    public function restoreMemento(Memento $memento) { // 将发起人恢复到备忘录对象记录的状态上
        $this->_state = $memento->getState();
    }
    public function setState($state) { $this->_state = $state; }
    public function getState() { return $this->_state; }
    public function showState() {}

}

class Memento { // 备忘录(Memento)角色
    private $_state;
    public function __construct($state) {
        $this->setState($state);
    }
    public function getState() { return $this->_state; }
    public function setState($state) { $this->_state = $state;}
}

class Caretaker { // 负责人(Caretaker)角色
    private $_memento;
    public function getMemento() { return $this->_memento; }
    public function setMemento(Memento $memento) { $this->_memento = $memento; }
}

// client
/* 创建目标对象 */
$org = new Originator();
$org->setState('open');
$org->showState();

/* 创建备忘 */
$memento = $org->createMemento();

/* 通过Caretaker保存此备忘 */
$caretaker = new Caretaker();
$caretaker->setMemento($memento);

/* 改变目标对象的状态 */
$org->setState('close');
$org->showState();

/* 还原操作 */
$org->restoreMemento($caretaker->getMemento());
$org->showState();
?>

优缺点

优点

缺点

参考

  1. Wikipedia: Memento pattern
  2. PHP设计模式笔记:使用PHP实现备忘录模式

访问者模式(Visitor pattern)

访问者模式是一种行为型模式,访问者表示一个作用于某对象结构中各元素的操作。它可以在不修改各元素类的前提下定义作用于这些元素的新操作,即动态的增加具体访问者角色。

访问者模式利用了双重分派。先将访问者传入元素对象的Accept方法中,然后元素对象再将自己传入访问者,之后访问者执行元素的相应方法。

主要角色

适用性

类图

visitor pattern

实例

<?php
interface Visitor { // 抽象访问者角色
    public function visitConcreteElementA(ConcreteElementA $elementA);
    public function visitConcreteElementB(concreteElementB $elementB);
}

interface Element { // 抽象节点角色
    public function accept(Visitor $visitor);
}

class ConcreteVisitor1 implements Visitor { // 具体的访问者1
    public function visitConcreteElementA(ConcreteElementA $elementA) {}
    public function visitConcreteElementB(ConcreteElementB $elementB) {}
}

class ConcreteVisitor2 implements Visitor { // 具体的访问者2
    public function visitConcreteElementA(ConcreteElementA $elementA) {}
    public function visitConcreteElementB(ConcreteElementB $elementB) {}
}

class ConcreteElementA implements Element { // 具体元素A
    private $_name;
    public function __construct($name) { $this->_name = $name; }
    public function getName() { return $this->_name; }
    public function accept(Visitor $visitor) { // 接受访问者调用它针对该元素的新方法
        $visitor->visitConcreteElementA($this);
    }
}

class ConcreteElementB implements Element { // 具体元素B
    private $_name;
    public function __construct($name) { $this->_name = $name;}
    public function getName() { return $this->_name; }
    public function accept(Visitor $visitor) { // 接受访问者调用它针对该元素的新方法
        $visitor->visitConcreteElementB($this);
    }
}

class ObjectStructure { // 对象结构 即元素的集合
    private $_collection;
    public function __construct() { $this->_collection = array(); }
    public function attach(Element $element) {
        return array_push($this->_collection, $element);
    }
    public function detach(Element $element) {
        $index = array_search($element, $this->_collection);
        if ($index !== FALSE) {
            unset($this->_collection[$index]);
        }
        return $index;
    }
    public function accept(Visitor $visitor) {
        foreach ($this->_collection as $element) {
            $element->accept($visitor);
        }
    }
}

// client
$elementA = new ConcreteElementA("ElementA");
$elementB = new ConcreteElementB("ElementB");
$elementA2 = new ConcreteElementB("ElementA2");
$visitor1 = new ConcreteVisitor1();
$visitor2 = new ConcreteVisitor2();

$os = new ObjectStructure();
$os->attach($elementA);
$os->attach($elementB);
$os->attach($elementA2);
$os->detach($elementA);
$os->accept($visitor1);
$os->accept($visitor2);
?>

优缺点

优点

缺点

参考

  1. Wikipedia: Visitor pattern
  2. Wikipedia: 访问者模式
  3. PHP设计模式笔记:使用PHP实现访问者模式

策略模式(Strategy pattern)

状态模式是一种行为型模式,它允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类,状态模式变化的位置在于对象的状态。

主要角色

适用性

类图

state pattern

实例

<?php
interface State { // 抽象状态角色
    public function handle(Context $context); // 方法示例
}

class ConcreteStateA implements State { // 具体状态角色A
    private static $_instance = null;
    private function __construct() {}
    public static function getInstance() { // 静态工厂方法,返还此类的唯一实例
        if (is_null(self::$_instance)) {
            self::$_instance = new ConcreteStateA();
        }
        return self::$_instance;
    }

    public function handle(Context $context) {
        $context->setState(ConcreteStateB::getInstance());
    }

}

class ConcreteStateB implements State { // 具体状态角色B
    private static $_instance = null;
    private function __construct() {}
    public static function getInstance() {
        if (is_null(self::$_instance)) {
            self::$_instance = new ConcreteStateB();
        }
        return self::$_instance;
    }

    public function handle(Context $context) {
        $context->setState(ConcreteStateA::getInstance());
    }
}

class Context { // 环境角色
    private $_state;
    public function __construct() { // 默认为stateA
        $this->_state = ConcreteStateA::getInstance();
    }
    public function setState(State $state) {
        $this->_state = $state;
    }
    public function request() {
        $this->_state->handle($this);
    }
}

// client
$context = new Context();
$context->request();
$context->request();
$context->request();
$context->request();
?>

优缺点

优点

参考

  1. Wikipedia: State pattern
  2. PHP设计模式笔记:使用PHP实现状态模式

抽象工厂模式(Abstract Factory pattern)

抽象工厂模式是一种创建型模式,它提供了一种方式,可以将一组具有同一主题的单独的工厂封装起来。它的实质是“提供接口,创建一系列相关或独立的对象,而不指定这些对象的具体类”。

抽象工厂模式提供一个创建一系统相关或相互依赖对象的接口,而无需指定它们具体的类。

抽象工厂模式中主要角色

这个和工厂方法模式类似,我们不再只要一个汉堡,可能是4个汉堡2个鸡翅,我们还是对服务员说,服务员属于具体工厂,抽象产品就是麦当劳可卖的食物,具体产品是我们跟服务员要的食物。

适用性

类图

abstract pattern

实例

<?php
class Button{}
class Border{}
class MacButton extends Button{}
class WinButton extends Button{}
class MacBorder extends Border{}
class WinBorder extends Border{}

interface AbstractFactory {
    public function CreateButton();
    public function CreateBorder();
}

class MacFactory implements AbstractFactory{
    public function CreateButton(){ return new MacButton(); }
    public function CreateBorder(){ return new MacBorder(); }
}
class WinFactory implements AbstractFactory{
    public function CreateButton(){ return new WinButton(); }
    public function CreateBorder(){ return new WinBorder(); }
}
?>

在这里例子中,工厂类实现了一组工厂方法。如果要增加新的功能,可以增加新的接口,让新的工厂类实现这个接口即可,而无需修改现有的工厂类。

优缺点

优点

缺点

难以支持新种类的产品。这是因为AbstractFactory接口确定了可以被创建的产品集合。支持新各类的产品就需要扩展访工厂接口,从而导致AbstractFactory类及其所有子类的改变。

参考

  1. Wikipedia: 抽象工厂
  2. Wikipedia: Abstract factory pattern
  3. PHP设计模式笔记:使用PHP实现抽象工厂模式

工厂方法模式(Factory method pattern)

工厂方法模式是一种创建型模式,这种模式使用“工厂”概念来完成对象的创建而不用具体说明这个对象。

在面向对象程序设计中,工厂通常是一个用来创建其他对象的对象。工厂是构造方法的抽象,用来实现不同的分配方案。

主要角色

工厂方法模式就像我们去麦当劳买汉堡,我们只要找到服务员,让他帮我们拿来汉堡即可。其中具体某个服务员就像具体工厂,他继承了服务员应有的服务。汉堡在到手以前属于抽象产品,而我们拿到的汉堡就属于具体产品。

适用性

类图

factory method

实例

普通工厂方法

下面的例子是工厂方法模式的应用,我们要创建两种风格的按钮,只需用不同的工厂方法获得相应按钮类即可。

<?php

class Button{/* ...*/}
class WinButton extends Button{/* ...*/}
class MacButton extends Button{/* ...*/}

interface ButtonFactory{
    public function createButton($type);
}

class MyButtonFactory implements ButtonFactory{
    // 实现工厂方法
    public function createButton($type){
        switch($type){
            case 'Mac':
                return new MacButton();
            case 'Win':
                return new WinButton();
        }
    }
}
?>

上例中的createButton()方法即所谓的工厂方法,它所在的类仅仅是这个方法的载体。工厂方法的核心功能是创建类并返回,这个方法可以产生一个类,也可以产生多种类。这个方法本身的载体也并不局限,将其设置为静态方法也是可以的,这个根据自己的情况而定。

优缺点

优点

工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。

缺点

参考

  1. Wikipedia: Factory method pattern
  2. Wikipedia: 工厂方法模式
  3. PHP设计模式笔记:使用PHP实现工厂模式

模板方法模式(Template method pattern)

模板方法模式模式是一种行为型模式,它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method 使得子类可以在不改变一个算法的结构的情况下重定义该算法的某些特定的步骤。

主要角色

抽象模板(AbstractClass)角色

定义一个或多个抽象方法让子类实现。这些抽象方法叫做基本操作,它们是顶级逻辑的组成部分。

定义一个模板方法。这个模板方法一般是一个具体方法,它给出顶级逻辑的骨架,而逻辑的组成步骤在对应的抽象操作中,这些操作将会推迟到子类中实现。同时,顶层逻辑也可以调用具体的实现方法

具体模板(ConcrteClass)角色

实现父类的一个或多个抽象方法,作为顶层逻辑的组成而存在。

每个抽象模板可以有多个具体模板与之对应,而每个具体模板有其自己对抽象方法(也就是顶层逻辑的组成部分)的实现,从而使得顶层逻辑的实现各不相同。

适用性

类图

template method pattern

实例

<?php
abstract class AbstractClass { // 抽象模板角色
    public function templateMethod() { // 模板方法 调用基本方法组装顶层逻辑
        $this->primitiveOperation1();
        $this->primitiveOperation2();
    }
    abstract protected function primitiveOperation1(); // 基本方法
    abstract protected function primitiveOperation2();
}

class ConcreteClass extends AbstractClass { // 具体模板角色
    protected function primitiveOperation1() {}
    protected function primitiveOperation2(){}

}

$class = new ConcreteClass();
$class->templateMethod();
?>

参考

  1. Wikipedia: Template method pattern
  2. Wikipedia: 模板方法模式
  3. PHP设计模式笔记:使用PHP实现模板方法模式

责任链模式(Chain of responsibility pattern)

责任链模式是一种行为型模式,它包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。该模式还描述了往该处理链的末尾添加新的处理对象的方法。

主要角色

实例

<?php
abstract class Responsibility { // 抽象责任角色
    protected $next; // 下一个责任角色

    public function setNext(Responsibility $l) {
        $this->next = $l;
        return $this;
    }
    abstract public function operate(); // 操作方法
}

class ResponsibilityA extends Responsibility {
    public function __construct() {}
    public function operate(){
        if (false == is_null($this->next)) {
            $this->next->operate();
        }
    };
}

class ResponsibilityB extends Responsibility {
    public function __construct() {}
    public function operate(){
        if (false == is_null($this->next)) {
            $this->next->operate();
        }
    };
}

$res_a = new ResponsibilityA();
$res_b = new ResponsibilityB();
$res_a->setNext($res_b);
?>

参考

  1. Wikipedia: Chain-of-responsibility pattern
  2. Wikipedia: 责任链模式
Table of Contents