design_pattern

对象就是数据,通过打印对象可查看

class object instance method property

$this

public private protected final  parent static clone const abstract

extend(一个,抽象类也能实现接口)  implements(多个,接口间也可以继承)

__construct  __destruct __set __get _call __callStatic  __toString  __isset __unset  __autoload __sleep  __wakeup

serialize unserialize 

this | self | parent


工厂 适配器 模板 解释器是通过继承实现,其他都是对象组合实现


MVC(观察者 组合 策略)

装饰者vs:不敢变接口,但加入责任 vs 

适配器vs:将一个接口转成另一个接口

外观vs:让接口更简单


模板:子类决定如何实现算法中的步骤  用继承

策略:封装可状态:封装基于状态的行为,然后委托决定采用哪一个  用组合 vs模板  vs状态

工厂:哪个具体类

组合:对象集合以及个别对象一视同仁

迭代:遍历集合,但不会暴露集合的实现

状态:封装基于状态的行为,并将行为委托到当前状态

代理:包装另一个对象,并控制对它的访问  vs 装饰器


/* 
  创建型

  1、系统架构技能之设计模式-单件模式 used

  2、系统架构技能之设计模式-工厂模式 used

  3、系统架构技能之设计模式-抽象工厂模式 used

  4、系统架构技能之设计模式-建造者模式 used

  5、系统架构技能之设计模式-原型模式 used

  结构型

  1、系统架构技能之设计模式-组合模式 used

  2、系统架构技能之设计模式-外观模式 used

  3、系统架构技能之设计模式-适配器模式 used

  4、系统架构技能之设计模式-桥模式 used

  5、系统架构技能之设计模式-装饰模式 used

  6、系统架构技能之设计模式-享元模式 used

  7、系统架构技能之设计模式-代理模式 used

  8、系统架构技能之设计模式-委托模式 used

  行为型

  1、系统架构技能之设计模式-命令模式 used

  2、系统架构技能之设计模式-观察者模式 used

  3、系统架构技能之设计模式-策略模式 used

  4、系统架构技能之设计模式-职责模式 used

  5、系统架构技能之设计模式-模板模式 used

  6、系统架构技能之设计模式-中介者模式 used

  7、系统架构技能之设计模式-解释器模式 used

  8、系统架构技能之设计模式-访问者模式 used
 * 
 * */
/*


  创建5--资源,控制对象个数  | 工厂+享元+原型+单例+建造
  
  工厂类动态创建类
  享元类加载工厂对象
  克隆原型类,__clong方法重写,
  单例类自动在其他类内部调用
  建造类创建目标类

  结构--扩展,控制类个数

  加工5:解释+迭代+外观+适配+装饰
  解释器类加载目标类,然后创建被解释类
  迭代器类创建目标类,并将对象集合存入数组
  外观类加载目标类对象
  第三方接口加载适配器对象
  装饰器类加载目标类

  重写3:模板+代理+数据访问
  模板类调父类方法
  代理类重写父类并调用
  数据访问类调用父类

  行为--通信,控制耦合程度

  交互7:委托+策略+中介+观察+访问+组合+桥梁
  目标类创建委托类
  目标类加载策略类对象
  目标类加载中介者对象,
  目标类加载观察者对象
  目标类加载访问者类对象
  目标类加载组合对象,迭代访问对象
  目标类加载桥梁对象

  链式3:职责+状态+命令
  职责类顺序加载其他职责对象,
  各状态顺序建立关系,目标类选取加载一个状态类对象,然后次第传递
  请求类加载值,命令类加载请求对象,接受类加载命令对象
 */
/*

  2.建造类调用基类,调用方法并传值,而后获取
  6.工厂类调用基类,实例化某个类调用统一接口实现多态化的功能,但它只实例化类,其他操作交给具体类实现,
  3.数据子类扩展基类,单独实现某种特有的增删方法,方便调用
  12.原型类调用父类,同时保有自身的独特属性和方法,通过clone复制,通过__clone重写
  13.自行创建并主动提供唯一实例,私有静态变量和私有构造方法以及访问实例的公共方法,对页面级请求共享同一对象有意义,避免重复创建实例的消耗


  10.迭代器类调用基类,调用方法并传值,随后将基类的对象赋给数组,而后通过循环判断拆分出基类对象取值
  11.外观类调用基类,传递给封装进来的其他类,然后其他类进行操作
  1.适配器类调父类,然后通过另一个某种功能的类去调用适配器类,实现某种功能转化
  4.装饰类调用基类,引用后修饰
  13.代理类调用父类,重写其中的方法
  18.组合模式是整体部分关系,各组合对象作为集合传给整体,然后循环获取
  19.桥模式,是多个类之间通过预定义方法,然后传入对象来调用,
  21.享元模式,工厂模式的精细化,如果已有了对象就不再生成,直接返回

  5.基类调用委托类,通过统一接口调用来实现功能的多态化
  8.基类调用中介类,而后调用中介类的方法,中介类会对其他类进行相关操作,而后再对本类进行操作
  9.基类调用观察者类,然后通知观察者,进行操作,观察者本身不变动,基类变动的话就行让观察者的访问数据也随之变化
  14.基类调用方法,传入策略类的对象,调用策略类方法,实现多态
  16.基类传入访问者类,并调用其中的方法,然后隐式执行,区别策略模式的显式执行

  7.解释器调用基类,并访问包含解释语句的方法,通过匹配后调用相关类的方法获取需要的值,合计后返回
  15.模板子类调用父类的方法,父类调用子类的方法,实现多态
  17.命令模式是请求者调用命令,命令调用响应者
  20.职责类继承父类,它们之间建立调用关系,形成调用链条,然后次第调用
  22.状态类之间建立传递关系,通过父类调用它,然后访问公共方法实现多态


 */



<?php
error_reporting(E_ALL);

ini_set('display_errors', '1');


工厂 适配器 模板 解释器是通过继承实现,其他都是对象组合实现


MVC(观察者 组合 策略)

装饰者vs:不敢变接口,但加入责任 vs 

适配器vs:将一个接口转成另一个接口

外观vs:让接口更简单


模板:子类决定如何实现算法中的步骤  用继承

策略:封装可状态:封装基于状态的行为,然后委托决定采用哪一个  用组合 vs模板  vs状态

工厂:哪个具体类

组合:对象集合以及个别对象一视同仁

迭代:遍历集合,但不会暴露集合的实现

状态:封装基于状态的行为,并将行为委托到当前状态

代理:包装另一个对象,并控制对它的访问  vs 装饰器

/* 
  创建型

  1、系统架构技能之设计模式-单件模式 used

  2、系统架构技能之设计模式-工厂模式 used

  3、系统架构技能之设计模式-抽象工厂模式 used

  4、系统架构技能之设计模式-建造者模式 used

  5、系统架构技能之设计模式-原型模式 used

  结构型

  1、系统架构技能之设计模式-组合模式 used

  2、系统架构技能之设计模式-外观模式 used

  3、系统架构技能之设计模式-适配器模式 used

  4、系统架构技能之设计模式-桥模式 used

  5、系统架构技能之设计模式-装饰模式 used

  6、系统架构技能之设计模式-享元模式 used

  7、系统架构技能之设计模式-代理模式 used

  8、系统架构技能之设计模式-委托模式 used

  行为型

  1、系统架构技能之设计模式-命令模式 used

  2、系统架构技能之设计模式-观察者模式 used

  3、系统架构技能之设计模式-策略模式 used

  4、系统架构技能之设计模式-职责模式 used

  5、系统架构技能之设计模式-模板模式 used

  6、系统架构技能之设计模式-中介者模式 used

  7、系统架构技能之设计模式-解释器模式 used

  8、系统架构技能之设计模式-访问者模式 used
 * 
 * */
/*


  创建5--资源,控制对象个数  | 工厂+享元+原型+单例+建造
  
  工厂类动态创建类
  享元类加载工厂对象
  克隆原型类,__clong方法重写,
  单例类自动在其他类内部调用
  建造类创建目标类

  结构--扩展,控制类个数

  加工5:解释+迭代+外观+适配+装饰
  解释器类加载目标类,然后创建被解释类
  迭代器类创建目标类,并将对象集合存入数组
  外观类加载目标类对象
  第三方接口加载适配器对象
  装饰器类加载目标类

  重写3:模板+代理+数据访问
  模板类调父类方法
  代理类重写父类并调用
  数据访问类调用父类

  行为--通信,控制耦合程度

  交互7:委托+策略+中介+观察+访问+组合+桥梁
  目标类创建委托类
  目标类加载策略类对象
  目标类加载中介者对象,
  目标类加载观察者对象
  目标类加载访问者类对象
  目标类加载组合对象,迭代访问对象
  目标类加载桥梁对象

  链式3:职责+状态+命令
  职责类顺序加载其他职责对象,
  各状态顺序建立关系,目标类选取加载一个状态类对象,然后次第传递
  请求类加载值,命令类加载请求对象,接受类加载命令对象
 */
/*

  2.建造类调用基类,调用方法并传值,而后获取
  6.工厂类调用基类,实例化某个类调用统一接口实现多态化的功能,但它只实例化类,其他操作交给具体类实现,
  3.数据子类扩展基类,单独实现某种特有的增删方法,方便调用
  12.原型类调用父类,同时保有自身的独特属性和方法,通过clone复制,通过__clone重写
  13.自行创建并主动提供唯一实例,私有静态变量和私有构造方法以及访问实例的公共方法,对页面级请求共享同一对象有意义,避免重复创建实例的消耗


  10.迭代器类调用基类,调用方法并传值,随后将基类的对象赋给数组,而后通过循环判断拆分出基类对象取值
  11.外观类调用基类,传递给封装进来的其他类,然后其他类进行操作
  1.适配器类调父类,然后通过另一个某种功能的类去调用适配器类,实现某种功能转化
  4.装饰类调用基类,引用后修饰
  13.代理类调用父类,重写其中的方法
  18.组合模式是整体部分关系,各组合对象作为集合传给整体,然后循环获取
  19.桥模式,是多个类之间通过预定义方法,然后传入对象来调用,
  21.享元模式,工厂模式的精细化,如果已有了对象就不再生成,直接返回

  5.基类调用委托类,通过统一接口调用来实现功能的多态化
  8.基类调用中介类,而后调用中介类的方法,中介类会对其他类进行相关操作,而后再对本类进行操作
  9.基类调用观察者类,然后通知观察者,进行操作,观察者本身不变动,基类变动的话就行让观察者的访问数据也随之变化
  14.基类调用方法,传入策略类的对象,调用策略类方法,实现多态
  16.基类传入访问者类,并调用其中的方法,然后隐式执行,区别策略模式的显式执行

  7.解释器调用基类,并访问包含解释语句的方法,通过匹配后调用相关类的方法获取需要的值,合计后返回
  15.模板子类调用父类的方法,父类调用子类的方法,实现多态
  17.命令模式是请求者调用命令,命令调用响应者
  20.职责类继承父类,它们之间建立调用关系,形成调用链条,然后次第调用
  22.状态类之间建立传递关系,通过父类调用它,然后访问公共方法实现多态


 */


/*
 * 模式之适配器模式,将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。——Gang of Four
  基本概念
  客户:需要调用我们的代码的对象。
  Adapter模式的宗旨:保留现有类所提供的服务,向客户提供接口,以满足客户的期望。
  主要内容
  (1)类适配器:
  当客户在接口中定义了他期望的行为时,我们就可以应用适配器模式,提供一个实现该接口的类,并且扩展已有的类,通过创建子类来实现适配。
  下面是类适配器的UML图:
  (2)对象适配器:
  对象适配器”通过组合除了满足“用户期待接口”还降低了代码间的不良耦合。在工作中推荐使用“对象适配”。下面是对象适配器的UML图:
  (3) 缺省适配器模式:
  缺省适配器模式是一种特殊的适配器模式,但这个适配器是由一个抽象类实现的,并且在抽象类中要实现目标接口中所规定的所有方法,但很多方法的实现都是“平庸”的实现,也就是说,这些方法都是空方法。而具体的子类都要继承此抽象类。
 */

class errorObject {

    private $_error;

    public function __construct($error) {
        $this->_error = $error;
    }

    public function getError() {
        return $this->_error;
    }

}

class logToCSV {

    const CSV_LOCATION = 'log.csv';

    private $_errorObject;

    public function __construct($errorObject) {
        $this->_errorObject = $errorObject;
    }

    public function write() {
        $line = $this->_errorObject->getErrorNumber();
        $line .=',';
        $line .=$this->_errorObject->getErrorText();
        $line .= "\n";
        file_put_contents(self::CSV_LOCATION, $line, FILE_APPEND);
    }

}

class logToCSVAdapter extends errorObject {

    private $_errorNumber, $_errorText;

    public function __construct($error) {
        parent::__construct($error); //parent后,始终调用父类方法
        $parts = explode(':', $this->getError());
        $this->_errorNumber = $parts[0];
        $this->_errorText = $parts[1];
    }

    public function getErrorNumber() {
        return $this->_errorNumber;
    }

    public function getErrorText() {
        return $this->_errorText;
    }

}

echo '适配器模式:'; //适配器对象传入第三方类
//explain 适配器类调父类的方法,然后通过另一个某种功能的类去调用适配器类,实现某种功能转化
//目标类和适配者类解耦,更换适配器要考虑目标类和接口类,系统整合的时候常用,系统需要使用现有的类,而这些类的接口不符合系统的接口
$error = new logToCSVAdapter("404:Not Found");
$log = new logToCSV($error);
$log->write();


/*
  模式之建造者模式,将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。
  1 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
  2 当构造过程必须允许被构造的对象有不同表示时。

  建造者模式关注的是的零件类型和装配工艺(顺序),这是它与工厂方法模式最大不同的地方,虽然同为创建类模式,但是注重点不同。

 */

class product {

    protected $_type = '';
    protected $_size = '';
    protected $_color = '';

    public function setType($type) {
        $this->_type = $type;
    }

    public function setSize($size) {
        $this->_size = $size;
    }

    public function setColor($color) {
        $this->_color = $color;
    }

}

class productBuilder {

    protected $_product = null;
    protected $_configs = array();

    public function __construct($configs) {//初始化传值
        $this->_product = new product(); //自行创建
        $this->_configs = $configs;
    }

    public function build() {
        $this->_product->setSize($this->_configs['size']);
        $this->_product->setType($this->_configs['type']);
        $this->_product->setColor($this->_configs['color']);
    }

    public function getProduct() {
        return $this->_product;
    }

}

echo '建造者模式:'; //建造类内部创建目标类
$productConfigs = array('type' => 'shirt2', 'size' => 'XL', 'color' => 'red');

//explain 建造者类中实例化基类,调用方法并传值,而后获取,内部创建后调用
//建造者是独立的,因此可以对建造过程逐步细化,更加注重组件类型和装配顺序,
$builder = new productBuilder($productConfigs);
$builder->build();
$product = $builder->getProduct();
print_r($product);


/* 模式之数据访问模式
  1.公开逻辑操作,封装物理操作——数据访问器抽象可以公开读、插入、更新和删除这样的逻辑数据库操作,而不需要应用程序代码发出SQL语句或者做类似的、低级的工作。
  2.公开逻辑资源,封装物理资源——向应用程序代码隐藏的越多,改变起来越自由。如果让应用程序管理自己的数据库连接,就很难在以后引入连接池、语句缓存或者数据分布这样的增强机制。
  3.规范化和格式化数据——数据的物理格式不一定是最适合应用程序处理的形式。特别是当来自多个数据库平台的格式不一致时。数据访问器的实现可以负责对这些字节进行串转换并交给应用程序一个对象表示。
  4.封装平台细节——业务关系不断变化。如果企业建立了新的合作关系而要求应用程序支持另外的数据库产品,那么把数据 库平台细节封装到数据访问器中实现有利于这种变化。
  5.封装优化细节——应用程序的性能不应该直接依赖于资源池和缓存这样的优化,否则就限制了将来改变这些优化的能力。如果只允许应用程序代码分配逻辑资源和发出逻辑操作,就把实现这些操作的自由留给数据访问器实现,它可以采用任何指定的优化策略。
 */

abstract class baseDAO {

    private $_connection;

    public function __construct() {
        $this->_connectToDB(DB_USER, DB_PASS, DB_HOST, DB_DATABASE);
    }

    private function _connectToDB($user, $pass, $host, $database) {
        $this->_connection = mysql_connect($host, $user, $pass);
        mysql_select_db($database, $this->_connection);
    }

    public function fetch($value, $key = NULL) {
        if (is_null($key)) {
            $key = $this->_primaryKey;
        }
        $sql = "select * from {$this->_tableName} where {$key}='{$value}'";
        $results = mysql_query($sql, $this->_connection);
        $rows = array();
        while ($result = mysql_fetch_assoc($results)) {
            $rows[] = $result;
        }
        return $rows;
    }

    public function update($keyArray) {
        $sql = "update {$this->_tableName} set ";
        $update = array();
        foreach ($keyArray as $column => $value) {
            $updates[] = "{$column} = '{$value}'";
        }
        $sql .= implode(',', $updates);
        $sql .= "where {$this->_primaryKey}='{$keyArray[$this->_primaryKey]}'";
// echo $sql;
        mysql_query($sql, $this->_connection);
    }

}

class userDAO extends baseDAO {

    protected $_tableName = 'userTable';
    protected $_primaryKey = 'id';

    public function getUserByFirstName($name) {
        $result = $this->fetch($name, 'firstName'); //调用父类方法
        return $result;
    }

}

define('DB_USER', 'root');
define('DB_PASS', 'root');
define('DB_HOST', 'localhost');
define('DB_DATABASE', 'test');
echo '数据访问模式:'; //数据访问类调用父类,
$user = new userDAO();
$userDetailArray = $user->fetch(1);
$updates = array('id' => 1, 'firstName' => 'change');
$user->update($updates);

//explain 数据子类扩展基类,单独实现某种特有的增删方法,方便调用,调用父类访问
//数据的组织和存储自然是数据库的天职了;而数据的处理则是跟专门的业务逻辑紧密联系的,复用的范围就缩小到了数据的访问以及数据的表示方面,

$allAarons = $user->getUserByFirstName('change');
var_dump($allAarons);


/* 模式之装饰器模式
  (1) 装饰对象和真实对象有相同的接口。这样客户端对象就可以和真实对象相同的方式和装饰对象交互。
  (2) 装饰对象包含一个真实对象的引用(reference)
  (3) 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
  (4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
 */

class CD {

    public $trackList;

    public function __construct() {
        $this->trackList = array();
    }

    public function addTrack($track) {
        $this->trackList[] = $track;
    }

    public function getTrackList() {
        $output = '';
        foreach ($this->trackList as $num => $track) {
            $output.= ($num + 1) . "){$track}.";
        }
        return $output;
    }

}

class CDTrackListDecoraterCaps {

    private $_cd;

    public function __construct($cd) {
        $this->_cd = $cd;
    }

    public function makeCaps() {
        foreach ($this->_cd->trackList as & $track) {//访问目标类的属性,并引用
            $track = strtoupper($track);
        }
    }

}

echo '装饰器模式:'; //目标类传入装饰器类
$tracksFromExternalSource = array('what it means', 'brr', 'goodbye');
$myCD = new CD();
foreach ($tracksFromExternalSource as $track) {
    $myCD->addTrack($track);
}

//explain 装饰类调用基类的属性,引用后修,传入对象访问
//它是对象的适配器模式的一种变种,过多使用会产生很多小对象,不易于管理
$myCDCaps = new CDTrackListDecoraterCaps($myCD);
$myCDCaps->makeCaps();
print "the cd contains" . $myCD->getTrackList();



/* 模式之委托模式
 * 委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。
 * 委托模式是一项基本技巧,许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。
 */

class newPlaylist {

    private $_songs;
    private $_typeObject;

    public function __construct($type) {
        $this->_songs = array();
        $object = "{$type}PlaylistDelegate";
        $this->_typeObject = new $object; //目标类创建委托类
    }

    public function addSong($location, $title) {
        $song = array('location' => $location, 'title' => $title);
        $this->_songs[] = $song;
    }

    public function getPlaylist() {
        $playlist = $this->_typeObject->getPlaylist($this->_songs); //目标类调用委托类
        return $playlist;
    }

}

class m3uPlaylistDelegate {

    public function getPlaylist($songs) {
        $m3u = "#EXTM3U\n\n";
        foreach ($songs as $song) {
            $m3u .= "#EXTINF:-1,{$song['title']}\n";
            $m3u .= "{$song['location']}\n";
        }
        return $m3u;
    }

}

class plsPlaylistDelegate {

    public function getPlaylist($songs) {
        $pls = "[playlist]\nNumberOfEntries = " . count($songs) . "\n\n";
        foreach ($songs as $songCount => $song) {
            $counter = $songCount + 1;
            $pls .= "File{$counter}={$song['location']}\n";
            $pls .= "Title{$counter}={$song['title']}\n";
            $pls .= "Length{$counter} = -1\n\n";
        }
        return $pls;
    }

}

echo '委托模式:'; //目标类调用委托类
$externalRetrievedType = 'm3u';
//explain 基类实例化委托类,通过统一接口调用来实现功能的多态化
$playlist = new newPlaylist($externalRetrievedType);
$playlist->addSong('/home/aaron/music/brr.mp3', 'Brr');
$playlist->addSong('/home/aaron/music/goodbye.mp3', 'Goodbye');

$playlistContent = $playlist->getPlaylist();
print_r($playlistContent);

/*
 * 模式之工厂模式
 * 工厂模式主要是为创建对象提供了接口。工厂模式按照《Java与模式》中的提法分为三类:
  1. 简单工厂模式(Simple Factory)
  2. 工厂方法模式(Factory Method)
  3. 抽象工厂模式(Abstract Factory)
  这三种模式从上到下逐步抽象,并且更具一般性。还有一种分类法,就是将简单工厂模式看为工厂方法模式的一种特例,两个归为一类。下面是使用工厂模式的两种情况:
  1.在编码时不能预见需要创建哪种类的实例。
  2.系统不应依赖于产品类实例如何被创建、组合和表达的细节

  三、简单工厂模式
  顾名思义,这个模式本身很简单,而且使用在业务较简单的情况下。
  它由三种角色组成(关系见下面的类图):
  1、工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑。在java中它往往由一个具体类实现。
  2、抽象产品角色:它一般是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。
  3、具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。
 * 
 * 工厂方法模式
  先来看下它的组成吧:
  1、抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
  2、具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。
  3、抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
  4、具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
  来用类图来清晰的表示下的它们之间的关系:
 */

class standardCD {

    public $title = '';
    public $band = '';
    public $tracks = array();

    public function __construct() {
        
    }

    public function setTitle($title) {
        $this->title = $title;
    }

    public function setBand($band) {
        $this->band = $band;
    }

    public function addTrack($track) {
        $this->tracks[] = $track;
    }

}

$title = 'Waste of a Rib';
$band = 'Never Again';
$tracksFromExternalSource = array('What It Means', 'Brrr', 'Goodbye');
$cd = new standardCD();
$cd->setTitle($title);
$cd->setBand($band);
foreach ($tracksFromExternalSource as $track) {
    $cd->addTrack($track);
}
echo '<pre>';
print_r($cd);

class enhancedCD {

    public $title = '';
    public $band = '';
    public $tracks = array();

    public function __construct() {
        $this->tracks[] = 'DATA TRACK';
    }

    public function setTitle($title) {
        $this->title = $title;
    }

    public function setBand($band) {
        $this->band = $band;
    }

    public function addTrack($track) {
        $this->tracks[] = $track;
    }

}

class CDFactory {

    public static function create($type) {
        $class = strtolower($type) . 'CD';
        return new $class; //工厂类创建目标类
    }

}

echo '工厂模式:'; //工厂类创建目标类
$type = 'enhanced';
//explain 工厂模式与委托模式类似,实例化某个类调用统一接口实现多态化的功能,但它只实例化类,其他操作交给具体类实现,
$cd = CDFactory::create($type);
$cd->setBand($band);
$cd->setTitle($title);
foreach ($tracksFromExternalSource as $track) {
    $cd->addTrack($track);
}
echo '<pre>';
print_r($cd);



/* 模式之解释器模式
  定义:给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子。
  解释器是一个简单的语法分析工具,它最显著的优点就是扩展性,修改语法规则只需要修改相应的非终结符就可以了,若扩展语法,只需要增加非终结符类就可以了。
  但是,解释器模式会引起类的膨胀,每个语法都需要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,而且用于解释一个解析复杂、冗长的语法时,效率是难以忍受的。

  有一个简单的语法规则,比如一个sql语句,如果我们需要根据sql语句进行rm转换,就可以使用解释器模式来对语句进行解释。
  一些重复发生的问题,比如加减乘除四则运算,有时是a+b-c*d,有时是a*b+c-d,公式千变万化,但是都是由加减乘除四个非终结符来连接的,使用解释器模式。
 */

class User {

    protected $_username = '';

    public function __construct($username) {
        $this->_username = $username;
    }

    public function getProfilePage() {
        $profile = "<h2> I like Never again!</h2>";
        $profile .= "I love all of their songs. My favorite CD:<br/>";
        $profile .= "{{myCD.getTitle}}!!"; //正则调用getTitle,然后字符串替换得到title
        return $profile;
    }

}

class userCD {

    protected $_user = NULL;

    public function setUser($user) {
        $this->_user = $user;
    }

    public function getTitle() {
        $title = 'Waste of a Rib';
        return $title;
    }

}

class userCDInterpreter {

    protected $_user = NULL;

    public function setUser($user) {
        $this->_user = $user;
    }

    public function getInterpreter() {
        $profile = $this->_user->getProfilePage();
        if (preg_match_all('/\{\{myCD\.(.*?)\}\}/', $profile, $triggers, PREG_SET_ORDER)) {
            $replacements = array();
            foreach ($triggers as $trigger) {
                $replacements[] = $trigger[1]; //trigger[0]是原字符串,trigger[1]是匹配后字符串
            }
            $replacements = array_unique($replacements);
            $myCD = new userCD();
            $myCD->setUser($this->_user);
            foreach ($replacements as $replacement) {
                $profile = str_replace("{{myCD.{$replacement}}}", call_user_func(array($myCD, $replacement)), $profile); //call_user_func 调用了$myCD类里的$replacement方法
            }
        }
        return $profile;
    }

}

echo '解释器模式:'; //目标类传入解释类,然后创建被解释类,通过字符解析获取信息
$username = 'aaron';
$user = new User($username);
//explain 解释器调用基类的对象,并访问包含解释语句的方法,通过匹配后调用相关类的方法获取需要的值,合计后返回
$interpreter = new userCDInterpreter();
$interpreter->setUser($user);
print "<h1> {$username} 's Profile </h1>";

print $interpreter->getInterpreter();



/* 模式之中介者模式
 * 中介者模式(Mediator Pattern):定义一个中介对象来封装系列对象之间的交互。
 * 中介者使各个对象不需要显示地相互引用,从而使其耦合性松散,而且可以独立地改变他们之间的交互。
 * 
 * 中介者模式又称为调停者模式,从类图中看,共分为3部分:
  抽象中介者:定义好同事类对象到中介者对象的接口,用于各个同事类之间的通信。一般包括一个或几个抽象的事件方法,并由子类去实现。
  中介者实现类:从抽象中介者继承而来,实现抽象中介者中定义的事件方法。从一个同事类接收消息,然后通过消息影响其他同时类。
  同事类:如果一个对象会影响其他的对象,同时也会被其他对象影响,那么这两个对象称为同事类。在类图中,同事类只有一个,这其实是现实的省略,在实际应用中,同事类一般由多个组成,他们之间相互影响,相互依赖。同事类越多,关系越复杂。并且,同事类也可以表现为继承了同一个抽象类的一组实现组成。在中介者模式中,同事类之间必须通过中介者才能进行消息传递。
 */

class CD2 {

    public $band = '';
    public $title = '';
    public $_mediator;

    public function __construct($mediator = null) {
        $this->_mediator = $mediator;
    }

    public function save() {
        echo '<pre>';
        echo 'cd';
        print_r($this);
    }

    public function changeBandName($newName) {
        if (!is_null($this->_mediator)) {
            $this->_mediator->change($this, array('band' => $newName));
        }
        $this->band = $newName;
        $this->save();
    }

}

class MP3Archive {

    public $band = '';
    public $title = '';
    protected $_mediator;

    public function __construct($mediator = null) {
        $this->_mediator = $mediator;
    }

    public function save() {
        echo '<pre>';
        echo 'mp3';
        print_r($this);
    }

    public function changeBandName($newName) {
        if (!is_null($this->_mediator)) {
            $this->_mediator->change($this, array('band' => $newName)); //注意输出的先后顺序
        }
        $this->band = $newName;
        $this->save();
    }

}

class MusicContainerMediator {

    protected $_containers = array();

    public function __construct() {
        $this->_containers[] = 'CD2';
        $this->_containers[] = 'MP3Archive'; //传入两个类
    }

    public function change($originalObject, $newValue) {
        $title = $originalObject->title;
        $band = $originalObject->band;

        foreach ($this->_containers as $container) {
            if (!($originalObject instanceof $container)) {//没传入的类进行创建,并操作
                $object = new $container;
                $object->title = $title;
                $object->band = $band;
                foreach ($newValue as $key => $val) {
                    $object->$key = $val;
                }
                $object->save();
            }
        }
    }

}

echo '中介者模式:'; //中介类传入目标类,然后目标类调用中介类的方法
$titleFromDB = 'Waste of a Rib';
$bandFromDB = 'Never Again';
//explain 用一个基类加载中介类的对象,而后调用中介类的方法,中介类会对其他类进行相关操作,而后再对本类进行操作
//降低了耦合性,但中介类承担了较多责任,
$mediator = new MusicContainerMediator();
$cd = new CD2($mediator);
$cd->title = $titleFromDB;
$cd->band = $bandFromDB;
$cd->changeBandName('Maybe Once More');



/* 模式之观察者模式
 * Observer模式的意图是“定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”。从这段话里我们可以得到两个信息,如下:
  1, 观察者(具体执行操作的对象,有多个)
  2, 被观察者(顾名思义是被观察的对象,如果该对象发生某些变化则通知观察者执行对应的操作)
 * 
 *  观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
 *  依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。
 */

class CDObserve {

    public $title = '';
    public $band = "";
    protected $_observers = array();

    public function __construct($title, $band) {
        $this->title = $title;
        $this->band = $band;
    }

    public function attachObserver($type, $observer) {//添加对象
        $this->_observers[$type][] = $observer;
        echo '<pre>';
        print_R($this->_observers);
    }

    public function notifyObserver($type) {
        if (isset($this->_observers[$type])) {
            foreach ($this->_observers[$type] as $observer) {
                $observer->update($this); //调用添加对象的方法
            }
        }
    }

    public function buy() {
        $this->notifyObserver("purchased");
    }

}

class buyCDNotifyStreamObserver {

    public function update(CDObserve $cd) { //目标类传入观察者类,定义某个类,自己保持不变,定义的相关类变了就随着变
        $activity = "The CD namde {$cd->title} by ";
        $activity.="{$cd->band} was just purchased ";
        activityStream::addNewItem($activity);
    }

}

class activityStream {

    public static function addNewItem($item) {
        print $item;
    }

}

echo '观察者模式:'; //观察者对象传入目标类,目标类调用观察者类,观察者类内部调用目标类
//当一个对象的改变需要给变其它对象时,而且它不知道具体有多少个对象有待改变时。解耦了观察者和被观察者,但不完全
$title = 'waste of a rib';
$band = 'never again';
$type = 'purchased';
$cd = new CDObserve($title, $band);
$observer = new buyCDNotifyStreamObserver();
// explain 基类加载观察者类,然后通知观察者,进行操作,观察者本身不变动,基类变动的话就行让观察者的访问数据也随之变化
$cd->attachObserver($type, $observer);
$cd->buy();



/* 模式之迭代器模式
 * 迭代器:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。
 * 迭代器模式由以下角色组成:

    1) 迭代器角色(Iterator):迭代器角色负责定义访问和遍历元素的接口。

    2) 具体迭代器角色(Concrete Iterator):具体迭代器角色要实现迭代器接口,并要记录遍历中的当前位置。

    3) 容器角色(Container):容器角色负责提供创建具体迭代器角色的接口。

    4) 具体容器角色(Concrete Container):具体容器角色实现创建具体迭代器角色的接口——这个具体迭代器角色于该容器的结构相关。

  由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加
 */

class CDITerator {

    public $band = '';
    public $title = '';
    public $trackList = array();

    public function __construct($band, $title) {
        $this->band = $band;
        $this->title = $title;
    }

    public function addTrack($track) {
        $this->trackList[] = $track;
    }

}

class CDSearchByBandITerator implements ITerator {

    private $_CDs = array();
    private $_valid = FALSE;

    public function __construct($bandName) {
        $db = mysql_connect('localhost', 'root', 'root');
        mysql_select_db('test');
        $sql = "select CD.id,CD.band,CD.title,tracks.tracknum, ";
        $sql .= "tracks.title as tracktitle";
        $sql .= " from CD left join tracks on CD.id = tracks.cid where band ='";
        $sql .= mysql_real_escape_string($bandName);
        $sql .= "' order by tracks.tracknum ";
        //echo $sql;
        $results = mysql_query($sql);
        $cdID = 0;
        $cd = NULL;
        while ($result = mysql_fetch_array($results)) {
            if ($result['id'] !== $cdID) {
                if (!is_null($cd)) {//存的上一趟的$cd,存储对象
                    $this->_CDs[] = $cd;
                }
                $cdID = $result['id'];
                $cd = new CDITerator($result['band'], $result['title']); //创建后被存入
            }
            $cd->addTrack($result['tracktitle']);
        }
        $this->_CDs[] = $cd; //最后一次遍历没存,存储一个类的数组
//        echo '<pre>';
//        print_r($this->_CDs);
    }

    public function next() {
        $this->_valid = (next($this->_CDs) === FALSE) ? FALSE : TRUE;
    }

    public function rewind() {
        $this->_valid = (reset($this->_CDs) === FALSE) ? FALSE : TRUE;
    }

    public function valid() {
        return $this->_valid;
    }

    public function current() {
        return current($this->_CDs);
    }

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

}

echo '迭代器模式:'; //迭代类内部创建目标类,然后存入数组成为对象集合
$queryItem = 'Never Again';
$cds = new CDSearchByBandIterator($queryItem);
print'<h1> found the following Cds </h1>';
print '<table> <tr> <th>Band</th><th>Title</th><th>NumTracks</th></tr>';

//explain 迭代器类会实例化基类,调用方法并传值,随后将基类的对象赋给数组,而后通过循环判断拆分出基类对象取值
while ($cds->valid($cds->next())) {
    foreach ($cds as $cd) {
        print "<tr><td>{$cd->band}</td><td>{$cd->title}</td><td>";
        print count($cd->trackList) . "</td></tr>";
    }
    print '</table>';
}



/* 模式之外观模式
  外观模式:为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用,如果过度封装,灵活性稍差。

  (1) Facade(外观角色):在客户端可以调用它的方法,在外观角色中可以知道相关的(一个或者多个)子系统的功能和责任;在正常情况下,它将所有从客户端发来的请求委派到相应的子系统去,传递给相应的子系统对象处理。

  (2) SubSystem(子系统角色):在软件系统中可以有一个或者多个子系统角色,每一个子系统可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每一个子系统都可以被客户端直接调用,或者被外观角色调用,它处理由外观类传过来的请求;子系统并不知道外观的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已。
 */

class CDAspects {

    public $tracks = array();
    public $band = '';
    public $title = '';

    public function __construct($title, $band, $tracks) {
        $this->title = $title;
        $this->band = $band;
        $this->tracks = $tracks;
    }

}

class CDUpperCase {

    public static function makeString(CDAspects $cd, $type) {//目标类
        $cd->$type = strtoupper($cd->$type);
    }

    public static function makeArray(CDAspects $cd, $type) {
        $cd->$type = array_map('strtoupper', $cd->$type);
    }

}

class CDMakeXML {

    public static function create(CDAspects $cd) {//目标类
        $doc = new DomDocument();
        $root = $doc->createElement('CD');
        $root = $doc->appendChild($root);
        $title = $doc->createElement('TITLE', $cd->title);
        $title = $doc->appendChild($title);
        $band = $doc->createElement('BAND', $cd->band);
        $band = $root->appendChild($band);
        $tracks = $doc->createElement('TRACKS');
        $tracks = $root->appendChild($tracks);
        foreach ($cd->tracks as $track) {
            $track = $doc->createElement('trackArray', $track);
            $track = $tracks->appendChild($track);
        }
        return $doc->saveXML();
    }

}

class WebServiceFacade {

    public static function makeXMLCall(CDAspects $cd) {
        CDUpperCase::makeString($cd, 'title');
        CDUpperCase::makeString($cd, 'band');
        CDUpperCase::makeArray($cd, 'tracks');
        $xml = CDMakeXML::create($cd);
        return $xml;
    }

}

echo '外观模式:'; //目标类传入外观类,统一封装后输出
$tracksFromExternalSource = array('What It Means', 'Brr', 'GoodBye');
$title = 'Waste of a Rib';
$band = 'Never Again';
$cd = new CDAspects($title, $band, $tracksFromExternalSource);
//explain 定义静态方法,外观类加载基类的对象,传递给封装进来的其他类,然后其他类进行操作
print WebServiceFacade::makeXMLCall($cd);
?>
<!--
<html>
    <head></head>
    <body>
    <cd>
        <band>NEVER AGAIN</band>
        <tracks>
            <trackarray>WHAT IT MEANS</trackarray>
            <trackarray>BRR</trackarray>
            <trackarray>GOODBYE</trackarray>
        </tracks>
    </cd>
    <title>WASTE OF A RIB</title>
</body>
</html>
-->
<?php
/*
  模式之原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。
  被复制的实例就是我们所称的“原型”,这个原型是可定制的。
  原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效;或者创建值相等,只是命名不一样的同类数据。
  缺点就是每一个类必须配备一个克隆方法。而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事。
 */

class CDPrototype {

    public $band = '';
    public $title = '';
    public $trackList = array();

    public function __construct($id) {
        $handle = mysql_connect('localhost', 'root', 'root');
        mysql_select_db('test', $handle);
        $query = "select band,title from CD where id = {$id}";
        //echo $query;

        $results = mysql_query($query, $handle);
        if ($row = mysql_fetch_assoc($results)) {
            $this->band = $row['band'];
            $this->title = $row['title'];
        }
    }

    public function buy() {
        echo '<pre>';
        print_r($this);
    }

}

class MixtapeCD extends CDPrototype {

    public function __clone() {
        $this->title = 'Mixtape';
    }

}

echo '原型模式:';
$externalPurchaseInfoBandID = 2;
$bandMixProto = new MixtapeCD($externalPurchaseInfoBandID); //克隆类实现__clone方法,重写后循环调用父类
$externalPurchaseInfo = array();
$externalPurchaseInfo[] = array('brrr', 'goodbye');
$externalPurchaseInfo[] = array('what it means', 'brrr');

foreach ($externalPurchaseInfo as $mixed) {
    //原型类重写父类的属性或方法,通过clone副本调用父类的方法同时有自己重写的属性和方法
    $cd = clone $bandMixProto; //克隆的是一个对象,
    $cd->trackList = $mixed;
    $cd->buy();
}


/*
  class mm {

  public $name = 'Peter';

  }

  $a = new mm();

  $b = $a;

  $c = &$a;

  $d = clone $a;

  $b->name = "Anne";

  echo $a->name, "\n", $b->name, "\n", $c->name, "\n", $d->name; //输出为:Anne Anne Anne Peter

 */

//在PHP5的类对象操作中,$a=$b和$a=&$b这种赋值方式,指向的是同一个对象,同一块内存空间;
//$a=clone $b这种赋值方式,则是指向另一个新的对象,另一个块新的内存空间。
//PHP对象复制可以通过clone关键字来完成,当对象被复制后,PHP5会对对象的所有属性执行一个浅复制(shallow copy),
//新对象所有的对其他对象的引用却是和老对象指向同一个地方,浅复制复制结构,不复制数据,深复制复制结构和数据

class Test1 {

    public $num1 = 0;
    //包含的对象  
    public $obj2;

    public function __construct() {
        $this->obj2 = new Test2;
    }

    public function __clone() {
        //实现深复制  
        $this->obj2 = clone $this->obj2; //克隆对象中的对象,此处执行了一个深复制,所有属性都创建了一个副本。
    }

}

class Test2 {

    public $num2 = 0;

}

$objNew = new Test1;
$obj = clone $objNew;
$objNew->num1 = 1;
$objNew->obj2->num2 = 2;

var_dump($obj->num1, $obj->obj2->num2);

/* 模式之代理模式
 * 其他对象提供一种代理以控制对这个对象的访问。
 * 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
 * 代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度,由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢
 */

class CDProxy {

    protected $_title = '';
    protected $_band = '';
    protected $_handle = null;

    public function __construct($title, $band) {
        $this->_title = $title;
        $this->_band = $band;
    }

    public function buy() {
        $this->_connect();
        $query = "update CD set bought=1 where band='";
        $query .= mysql_real_escape_string($this->_band, $this->_handle);
        $query .= "'and title='";
        $query .= mysql_real_escape_string($this->_title, $this->_handle);
        $query .= "'";
        echo $query;
        mysql_query($query, $this->_handle);
    }

    protected function _connect() {
        $this->_handle = mysql_connect('localhost', 'root', 'root');
        mysql_select_db('cd', $this->_handle);
    }

}

class DallaNOCCDProxy extends CDProxy {

    protected function _connect() {
        $this->_handle = mysql_connect('localhost', 'root', 'root');
        mysql_select_db('test');
    }

}

echo '代理模式:'; //子类覆盖重写父类
$externalTitle = 'Waste of a Rib';
$externalBand = 'Never Again';
//代理类调用父类,
$cd = new DallaNOCCDProxy($externalTitle, $externalBand);
$cd->buy();



/* 模式之单例模式
 * 流程:一个类只有一个实例,并提供一个全局访问点
  一、某个类只能有一个实例;
  二、它必须自行创建这个实例;
  三、向整个系统提供这个实例;
 * 
  构件:
  需要一个保存类的唯一实例的静态成员变量(通常$instance为私有变量)
  构造函数和克隆函数必须声明为私有的,为了防止外部程序new类从而失去单例模式意义
  必须提供一个访问这个实例的公共静态方法,从而返回唯一实例的一个引用

  作用:
  1,PHP主要应用在数据库中的开发应用,这样会对数据库进行频繁的操作,而使用PHP单例模式,能避免大量的new资源的开销!
  2 ,如果系统只需要一个类来全局控制配置某些配置信息,那么使用单例模式可以方面简单的实现。
  3,在一次页面中请求中,因为所有的代码都集中在一个类中,例如数据库的操作,我们可以在类中设置钩子,输出日子,从而避免页面大量的var_dum、echo等调试信息。

 * 我用php大部分操作都是和各种数据库打交道,包括mysql,redis,memcache等各种关系型和非关系型数据库,
 * 所以一个应用中会存在大量连接数据库的操作,如果不用单例模式,那每次都要new操作,
 * 但是每次new都会消耗大量的内存资源和系统资源,而且每次打开和关闭数据库连接都 是对数据库的一种极大考验和浪费。
 * 
 * 底层:
 * PHP语言是一种解释型的脚本语言,这种运行机制使得每个PHP页面被解释执行后,所有的相关资源都会被回收。
 * 也就是说,PHP在语言级别上没有办法让某个对象常驻内存,这和asp.net、Java等编译型是不同的,
 * 比如在Java中单例会一直存在于整个应用程序的生命周期里,变量是跨页面级的,真正可以做到这个实例在应用程序生命周期中的唯一性。
 * 然而在PHP中,所有的变量无论是全局变量还是类的静态成员,都是页面级的,每次页面被执行时,都会重新建立新的对象,都会在页面执行完毕后被清空,这样似乎PHP单例模式就没有什么意义了,
 * 所以PHP单例模式我觉得只是针对单次页面级请求时出现多个应用场景并需要共享同一对象资源时是非常有意义的。
 * 
 * 小结:自行创建并主动提供唯一实例,私有静态变量和私有构造方法以及访问实例的公共方法,对页面级请求共享同一对象有意义,避免重复创建实例的消耗
 *  */

class InventoryConnection {

    protected static $_instance = NULL; //私有变量存实例
    protected $_handle = NULL;

    public static function getInstance() {//公共方法访问实例
        if (!self::$_instance instanceof self) {
            self::$_instance = new self;
        }
        return self::$_instance;
    }

    protected function __construct() {//私有构造方法,防止外部创建
        $this->_handle = mysql_connect('localhost', 'root', 'root');
        mysql_select_db('test', $this->_handle);
    }

    public function updateQuantity($band, $title, $number) {
        $query = "update CD set bought=bought" . (intval($number));
        $query .= " where band='" . mysql_real_escape_string($band) . "'";
        $query .= " and title='" . mysql_real_escape_string($title) . "'";
        //echo $query;
        mysql_query($query, $this->_handle);
    }

}

class CDSingle {

    protected $_title = '';
    protected $_band = '';

    public function __construct($title, $band) {
        $this->_title = $title;
        $this->_band = $band;
    }

    public function buy() {
        $inventory = InventoryConnection :: getInstance();
        $inventory->updateQuantity($this->_band, $this->_title, -1);
    }

}

echo '单例模式:'; //目标类调用单例类,单例类内部创建唯一实例
$boughtCDs = array();
$boughtCDs[] = array('band' => 'Never Again', 'title' => 'Waste of a Rib');
$boughtCDs[] = array('band' => 'Therapee', 'title' => 'Long Road');
foreach ($boughtCDs as $boughtCD) {
    $cd = new CDSingle($boughtCD['title'], $boughtCD['band']);
    $cd->buy();
}


/* 模式之策略模式
 * 它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。
 * 优点:

    1、 简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。
    2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
  3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。

    缺点:
    1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
  2、 在基本的策略模式中,选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。(这本身没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式结合后,选择具体实现的职责也可以由Context来承担,这就最大化的减轻了客户端的压力。)

 * 区别:
 * 小结:策略需要客户端选择创建对象后统一执行,工厂直接创建对象
 * 简单的说,工厂类的使用者需要不是自己创建的对象,策略模式中Context类的使用者需要的是自己创建的对象。
  更简单的说,工厂模式:我没有,我需要你的。策略模式:我自己有,我用我自己的。
 * 
 * 更简洁的说是定义策略族,分别封装起来,让他们之间可以相互替换,策略模式让策略的变化独立于使用策略的客户。
 * 而工厂模式主要解决的是资源的统一分发,将对象的创建完全独立出来,让对象的创建和具体的使用客户无关。
 *  */

class CDusesStrategy {

    public $title = '';
    public $band = '';
    protected $_strategy;

    public function __construct($title, $band) {
        $this->title = $title;
        $this->band = $band;
    }

    public function setStrategyContext($strategyObject) {
        $this->_strategy = $strategyObject;
    }

    public function get() {
        return $this->_strategy->get($this);
    }

}

class CDAsXMLStrategy {

    public function get(CDusesStrategy $cd) {  //策略类传入目标类
        $doc = new DomDocument();
        $root = $doc->createElement('CD');
        $root = $doc->appendChild($root);
        $title = $doc->createElement('Title', $cd->title);
        $title = $root->appendChild($title);
        $band = $doc->createElement('BAND', $cd->band);
        $band = $root->appendChild($band);
        return $doc->saveXML();
    }

}

class CDAsJSONStrategy {

    public function get(CDusesStrategy $cd) { //策略类传入目标类
        $json = array();
        $json['CD']['title'] = $cd->title;
        $json['CD']['band'] = $cd->band;
        return json_encode($json);
    }

}

echo '策略模式:'; //策略类对象传入目标类,目标类间接调用策略类,策略类中再包含目标类,访问目标类的属性和方法
$externalBand = 'Never Again';
$externalTitle = 'Waste of a Rib';
$cd = new CDusesStrategy($externalTitle, $externalBand);
//基类调用方法,传入策略类的对象,实现多态
$cd->setStrategyContext(new CDAsXMLStrategy());
print $cd->get($cd);
$cd->setStrategyContext(new CDAsJSONStrategy());
print $cd->get($cd);


/*
 * 模式之模板模式准备一个抽象类,将部分逻辑以具体方法以及具体构造子的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。
 * 先制定一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。开闭原则是指一个软件实体应该对扩展开放,对修改关闭。
 * 模板方法模式意图是由抽象父类控制顶级逻辑,并把基本操作的实现推迟到子类去实现,这是通过继承的手段来达到对象的复用,同时也遵守了开闭原则!
 */

abstract class SaleItemTemplate {

    public $price = 0;

    public final function setPriceAdjustments() { //不可重写,统一调用
        $this->price += $this->taxAddition();
        $this->price += $this->oversizeAddition();
    }

    protected function oversizeAddition() {
        return 0;
    }

    abstract protected function taxAddition();
}

class CDTemplate extends SaleItemTemplate {//继承并可选择地实现抽象类

    public $band;
    public $title;

    public function __construct($band, $title, $price) {
        $this->band = $band;
        $this->title = $title;
        $this->price = $price;
    }

    protected function taxAddition() {
        echo $this->price;
        return round($this->price * 0.05, 2);
    }

}

class BandEndorsedCaseOfCereal extends SaleItemTemplate {

    public $band;

    public function __construct($band, $price) {
        $this->band = $band;
        $this->price = $price;
    }

    protected function taxAddition() {
        return 0;
    }

    protected function oversizeAddition() {
        echo $this->price;
        return round($this->price * 0.20, 2);
    }

}

echo '模板模式:'; //子类调用父类方法,通过父类统一接口实现各自方法
$externalTitle = 'Waste of a Rib';
$externalBand = 'Never Again';
$externalCDPrice = 12.99;
$externalCerealPrice = 90;

//模板子类调用父类的方法,父类调用子类的方法,实现多态
$cd = new CDTemplate($externalBand, $externalTitle, $externalCDPrice);
$cd->setPriceAdjustments();
print 'the total cost for cd item is:$' . $cd->price . '<br/>';

$cereal = new BandEndorsedCaseOfCereal($externalBand, $externalCerealPrice);
$cereal->setPriceAdjustments();
print 'the total cost for the Cereal case is :$' . $cereal->price;




/* 模式之访问者模式
 * 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
 * 在我看来可以把访问者模式想象成策略模式的扩展版,都是实现对象在不同情况下的不同表现,只是状态与策略主要是针对一种对象,而访问者是针对多种对象。
  但增加新元素比较困难,每增加一个元素类都需要修改访问者类
 *  */

class CDVisitor {

    public $band;
    public $title;
    public $price;

    public function __construct($band, $title, $price) {
        $this->band = $band;
        $this->title = $title;
        $this->price = $price;
    }

    public function buy() {
        //stub
    }

    public function acceptVisitor($visitor) {
        $visitor->visitCD($this); //传入目标类对象
    }

}

class CDVisitorLogPurchase {

    public function visitCD($cd) {//传入目标类
        $logline = "{$cd->title} by {$cd->band} was purchased for {$cd->price}";
        $logline .= " at " . date('r') . "\n";
        file_put_contents('/var/www/html/pattern/purchases.log', $logline, FILE_APPEND);
    }

}

class CDVisitorPopulateDiscountList {

    public function visitCD($cd) {//传入目标类
        if ($cd->price < 20) {
            $this->_populateDiscountList($cd);
        }
    }

    protected function _populateDiscountList($cd) {
        $logline = "{$cd->title} by {$cd->band} was very cheap purchased for {$cd->price}";
        $logline .= " at " . date('r') . "\n";
        file_put_contents('/var/www/html/pattern/purchases.log', $logline, FILE_APPEND);
    }

}

echo '访问者模式:'; //访问者类传入目标类,目标类调用访问者类,访问者类调用目标类的属性和方法
$externalBand = 'Never Again';
$externalTitle = 'Waste of a Rib';
$externalPrice = 19.99;
$cd = new CDVisitor($externalBand, $externalTitle, $externalPrice);
$cd->buy();
//基类传入访问者类,并调用其中的方法,然后隐式执行,区别策略模式的显式执行
$cd->acceptVisitor(new CDVisitorLogPurchase());
$cd->acceptVisitor(new CDVisitorPopulateDiscountList());



/*
 * 模式之命令模式:将一个请求封装为一个对象,从而你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销操作。
  命令类:
  1.命令角色:声明了一个给所有具体命令类的抽象接口。这是一个抽象角色。
  2.具体命令角色:定义一个接受者和行为之间的弱耦合;实现execute方法,负责调用接受的相应操作。execute()方法通常叫做执行方法
  3.客户角色:创建一个具体命令对象并确定其接受者。
  4.请求者角色:负责调用命令对象执行请求,相关的方法叫做行动方法。
  5.接受者角色:负责具体实施和执行一个请求。
  作用:
  1.抽象出待执行的动作以参数化对象。
  2.在不同的时刻指定、排列和执行请求。
  3.支持取消操作
  4.支持修改日志
 * 
  系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
 * 因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。
 */

//命令接口
interface Command {

    public function execute();
}

//具体命令
class ConcreteCommand implements Command {

    private $_receiver;

    public function __construct($receiver) {
        $this->_receiver = $receiver;
    }

    public function execute() {
        $this->_receiver->action(); //调用接受者
    }

}

//接受者
class Receiver {

    private $_name;

    public function __construct($name) {
        $this->_name = $name;
    }

    //行动方法
    public function action() {
        echo $this->_name . ' do action .<br/>';
    }

}

//请求者
class Invoker {

    private $_command;

    public function __construct($command) {
        $this->_command = $command;
    }

    public function action() {
        $this->_command->execute(); //调用命令者
    }

}

//客户端
class Client {

    public static function main() {
        //命令模式是请求者调用命令,命令调用响应者
        $receiver = new Receiver('jaky');
        $command = new ConcreteCommand($receiver);
        $invoker = new Invoker($command);
        $invoker->action();
    }

}

//层层传递对象,逆向操作
echo '命令模式:';
Client::main();



/*
  模式之组合模式有时候又叫做部分-整体模式,它把程序内部简单元素和复杂元素提供给客户端统一的接口,
  使客户端和程序的内部结构结构,内部可以随意更改扩展。
 */

/**
 * 单元抽象类 
 */
abstract class Unit {

    /**
     * 作战能力 
     * 
     */
    abstract function bombardStrength();
}

/**
 * 弓箭手 
 * @author li.yonghuan 
 * @version 2014.01.15 
 * 
 */
class Archer extends Unit {

    /**
     * 作战能力 
     * 
     */
    public function bombardStrength() {
        return '4';
    }

}

/**
 * 激光大炮单元 
 * @author li.yonghuan 
 * @version 2014.01.15 
 */
class laserCannonUnit extends Unit {

    /**
     * 作战能力 
     * 
     */
    public function bombardStrength() {
        return '42';
    }

}

/**
 * 军队 
 * @author li.yonghuan 
 * @version 2014.01.15 
 */
class Arm {

    /**
     * 存储作战单元的数组 
     * @var array 
     */
    private $units = array();

    /**
     * 添加单元 
     * @param Unit object 
     */
    public function addUnit(Unit $unit) {
        array_push($this->units, $unit);
    }

    /**
     * 作战能力 
     * 
     */
    public function bombardStrength() {
        $strength = 0;
        foreach ($this->units as $unit) {
            $strength += $unit->bombardStrength();
        }
        return $strength;
    }

}

//整合类加载组合类,迭代访问组合类的内部方法
echo '组合模式:';
$archer = new Archer();
$laserCannon = new laserCannonUnit();
//组合模式是整体部分关系,各组合对象作为集合传给整体,然后循环获取,有点像迭代模式的意思
$arm = new Arm();
$arm->addUnit($archer);
$arm->addUnit($laserCannon);
echo $arm->bombardStrength();

/**
 * 模式之桥接模式
 *
 * 将抽象部份与它实现部分分离,使用它们都可以有独立的变化
 */
abstract class Implementor {

    abstract public function operation();
}

class ConcreteImplementorA extends Implementor {//具体实现类

    public function operation() {
        echo "ConcreteImplementorA Operation<br/>";
    }

}

class ConcreteImplementorB extends Implementor {

    public function operation() {
        echo "ConcreteImplementorB Operation<br/>";
    }

}

class Abstraction {

    protected $_implementor = null;

    public function setImplementor($implementor) {//传入实现的对象
        $this->_implementor = $implementor;
    }

    public function operation() {
        $this->_implementor->operation();
    }

}

class RefinedAbstraction extends Abstraction {
    
}

class ExampleAbstraction extends Abstraction {
    
}

//具体实现对象传入目标类,然后统一调用
echo '桥接模式:';
//多个类之间通过预定义方法,然后传入对象来调用,
$objRAbstraction = new RefinedAbstraction();
$objRAbstraction->setImplementor(new ConcreteImplementorB());
$objRAbstraction->operation();
$objRAbstraction->setImplementor(new ConcreteImplementorA());
$objRAbstraction->operation();

$objEAbstraction = new ExampleAbstraction();
$objEAbstraction->setImplementor(new ConcreteImplementorB());
$objEAbstraction->operation();

/**
 * 职责链模式
 *
 * 为解除请求的发送者和接收者之间的耦合,而使用多个对象都用机会处理这个请求,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它
 * 那么当这个链结构比较长,比较复杂的话,会产生很多的内存垃圾对象。
 */
abstract class Handler {

    protected $_handler = null;

    public function setSuccessor($handler) {
        $this->_handler = $handler;
    }

    abstract function handleRequest($request);
}

class ConcreteHandlerZero extends Handler {

    public function handleRequest($request) {
        if ($request == 0) {
            echo "0<br/>";
        } else {
            $this->_handler->handleRequest($request); //调用父类属性和方法
        }
    }

}

class ConcreteHandlerOdd extends Handler {

    public function handleRequest($request) {
        if ($request % 2) {
            echo $request . " is odd<br/>";
        } else {
            $this->_handler->handleRequest($request);
        }
    }

}

class ConcreteHandlerEven extends Handler {

    public function handleRequest($request) {
        if (!($request % 2)) {
            echo $request . " is even<br/>";
        } else {
            $this->_handler->handleRequest($request);
        }
    }

}

echo '职责链模式:'; //职责类顺序加载其他职责类,通过判断,如条件满足就访问父类的属性和对应职责类方法,
// 实例一下
$objZeroHander = new ConcreteHandlerZero();
$objEvenHander = new ConcreteHandlerEven();
$objOddHander = new ConcreteHandlerOdd();
//职责类继承父类,它们之间建立调用关系,形成调用链条,然后次第调用
$objZeroHander->setSuccessor($objEvenHander);
$objEvenHander->setSuccessor($objOddHander);
foreach (array(2, 3, 4, 5, 0) as $row) {
    $objZeroHander->handleRequest($row);
}

/**
 * 模式之享元模式
 *
 * 运用享元技术有效的支持大量细粒度的对象
 */
class CDFlyweight {

    private $_title = null;
    private $_artist = null;

    public function setTitle($title) {
        $this->_title = $title;
    }

    public function getTitle() {
        return $this->_title;
    }

    public function setArtist($artist) {
        $this->_artist = $artist;
    }

    public function getArtist($artist) {
        return $this->_artist;
    }

}

class Artist {

    private $_name;

    public function __construct($name) {
        echo "construct " . $name . "<br/>";
        $this->_name = $name;
    }

    public function getName() {
        return $this->_name;
    }

}

class ArtistFactory {

    private $_artists = array();

    public function getArtist($name) {
        if (isset($this->_artists[$name])) {
            return $this->_artists[$name];
        } else {
            $objArtist = new Artist($name);
            $this->_artists[$name] = $objArtist; //存在数组中,下回就不用new了,直接return就行了
            print_r($this->_artists);
            return $objArtist;
        }
    }

}

//工厂对象传入目标类的方法,然后访问内置对象后决定是否创建工厂类
echo '享元模式:';
$objArtistFactory = new ArtistFactory();
//工厂模式的精细化,如果已有了对象就不再生成,直接返回
$objCD1 = new CDFlyweight();
$objCD1->setTitle("title1");
$objCD1->setArtist($objArtistFactory->getArtist('artist1'));

//print_r($objCD1);
$objCD2 = new CDFlyweight();
$objCD2->setTitle("title2");
$objCD2->setArtist($objArtistFactory->getArtist('artist2'));
//print_r($objCD2);

$objCD3 = new CDFlyweight();
$objCD3->setTitle("title3");
$objCD3->setArtist($objArtistFactory->getArtist('artist1'));
//print_r($objCD3);

/**
 * 状态模式
 *
 * 允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它所属的类
 * 不足是这种链条会产生大量实现类
 *
 */
interface State {

    public function handle($state); //状态

    public function display();
}

class Context {

    private $_state = null;

    public function __construct($state) {
        $this->setState($state);
    }

    public function setState($state) {
        $this->_state = $state;
    }

    public function request() {
        $this->_state->display();
        echo '<pre>';
        print_r($this);
        $this->_state->handle($this); //传入自己
    }

}

class StateA implements State {

    public function handle($context) {
        $context->setState(new StateB()); //调用了Context的setState
    }

    public function display() {
        echo "state A<br/>";
    }

}

class StateB implements State {

    public function handle($context) {
        $context->setState(new StateC());
    }

    public function display() {
        echo "state B<br/>";
    }

}

class StateC implements State {

    public function handle($context) {
        $context->setState(new StateA());
    }

    public function display() {
        echo "state C<br/>";
    }

}

//不同状态类建立调用顺序,然后通过目标类统一调用实现
echo '状态模式:';
// 实例化一下
//状态类之间建立传递关系,通过父类调用它,然后访问公共方法实现多态
$objContext = new Context(new StateA());
$objContext->request();
$objContext->request();
$objContext->request();
$objContext->request();




/*

  SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
  SET time_zone = "+00:00";

--
--Database: `test`
--
----------------------------------------------------------
--
--表的结构 `tracks`
--
CREATE TABLE IF NOT EXISTS `tracks` (
`cid` int(11) NOT NULL AUTO_INCREMENT,
 `title` varchar(22) NOT NULL,
 `tracknum` varchar(22) NOT NULL,
 PRIMARY KEY (`cid`)
) ENGINE = MyISAM DEFAULT CHARSET = latin1 AUTO_INCREMENT = 9;

--
--转存表中的数据 `tracks`
--
INSERT INTO `tracks` (`cid`, `title`, `tracknum`) VALUES
(1, 'ok1', 'ok1'),
 (2, 'ok2', 'ok2'),
 (3, 'ok1', 'ok1'),
 (4, 'ok2', 'ok2'),
 (5, 'ok1', 'ok1'),
 (6, 'ok2', 'ok2'),
 (7, 'ok3', 'ok3'),
 (8, 'ok4', 'ok4');


--phpMyAdmin SQL Dump
--version 4.1.4
--http://www.phpmyadmin.net
--
--Host: localhost
--Generation Time: 2014-06-26 16:32:22
--服务器版本: 5.1.73-log
--PHP Version: 5.3.3

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";



--
--Database: `test`
--
----------------------------------------------------------
--
--表的结构 `CD`
--
CREATE TABLE IF NOT EXISTS `CD` (
`id` int(11) NOT NULL AUTO_INCREMENT,
 `band` varchar(222) NOT NULL,
 `title` varchar(222) NOT NULL,
 `bought` int(11) NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE = MyISAM DEFAULT CHARSET = latin1 AUTO_INCREMENT = 6;

--
--转存表中的数据 `CD`
--
INSERT INTO `CD` (`id`, `band`, `title`, `bought`) VALUES
(1, 'Never Again', 'title', 0),
 (2, 'Never Again', 'another ok', 0),
 (3, 'Never Again', 'Waste of a Rib', 0),
 (4, 'Never Again', 'another title', 0),
 (5, 'Never Again', 'try it', 0);

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值