适配器模式

适配器设计模式只是将某个对象的接口适配为另一个对象所期望的接口

基类-》对象引用基类 适配器adapter继承基类,并实现新方法-》对象引用adapter类 例如;基类有设置和获取名称两个方法,现在需要活动名称的长度;这时新建一个adapter类继承基类,并实现新方法获取长度

//设置名称并打印
class GetName{
    private $name;
    public function getName(){
        return $this->name;
    }
    public function setName($name){
        $this->name = $name;
    }
}


$user = new GetName();
$user->setName('adapter');
var_dump($user->getName());


//新需求,要打印名称的长度
class GetNameApater extends GetName{
    public function __construct(){
        parent::__contruct();
    }
    public function getNameLength(){
        return strlen($this->name);
    }
}
$user = new GetName();
$user->setName('adapter');
var_dump($user->getName());
var_dump($user->getNameLength());

建造者模式

建造者设计模式定义了处理其他对象的复杂构建的对象设计

初始化对象时需要设置多个默认值或调用其他方法时

建造者设计模式的目的是为了消除其他对象的复杂创建过程。使用建造者设计模式可以在某个对象的构造和配置方法改变时尽可能的减少重复更改代码

//初始化一个产品类
class product{
    protected $type;
    protected $num;
    protected $name;
    public function setType($type){
        $this->type = $type;
    }
    public function setNum($num){
        $this->num = $num;
    }
    public function setName($name){
        $this->name = $name;
    }
}
//使用方式
$product = new product();
$product->setType('type');
$product->setNum(10);
$product->setName('name');


//建造者模式
class productBuilder{
    protected $_product = NULL;
    protected $_configs = [];
    public function __construct($config){
        $this->_product = new product();
        $this->_configs = $config;
    }
    public function build(){
        $this->_product->setType($this->_configs['type']);
        $this->_product->setNum($this->_configs['num']);
        $this->_product->setName($this->_configs['name']);
    }
    public function getProduct(){
        return $this->_product;
    }
}

$builder = new productBuilder($configs);
$builder->build();
$product = $builder->getProduct();

数据访问对象模式

数据访问对象设计模式描述了如何创建提供透明访问任何数据源的对象 为了减少重复和抽象化数据,最好的方法是基于数据访问对象创建一个类

abstract class baseDAO{
    private $_connection;
    public function __construct(){
        $this->_connectDB(DB_USER,DB_PASS,DB_HOST,DB_DATABASE);
    }
    public function _connectDB($user,$pass,$host,$db){
        $this->_connection = mysql_connect($host,$user,$pass);
        mysql_select_db($db,$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 = [];
        while($result = mysql_fetch_array($results)){
            $rows[] = $result;
        }
        return $rows;
    }
    public function update($keyArray){
        $sql = "update {$this->_tableName} set ";
        $updates = [];
        foreach($keyArray as $column=>$value){
            $updates[] = "{$column}='{$value}' ";
        }
        $sql .= implode(',',$updates);
        $sql .= "where {$this->_primaryKey}='{$keyArray[$this->_primaryKey]}'"
    }
}


class userDAO extends baseDAO{
    protected $_tableName = 'userTable';
    protected $_primaryKey = 'id';
    public function getUserByFirstName($name){
        $result = $this->fetch($name,'firstname');
        return $result;
    }
}


define('DB_USER','user');
define('DB_PASS','pass');
define('DB_HOST','localhost');
define('DB_DATABASE','test');

$user = new userDAO();

$userDetailsArray = $user->fetch(1);

$updates = ['id' =>  1,'firstName' => 'test'];
$user->update($updates);

$allTestUser = $user->getUserByFirstName('test');

装饰器模式

如果已有对象的部分内容或功能性发生改变,但是不需要修改原始对象的结构,那么使用装饰器设计模式最合适 当引入的需求要求在不影响现有基本代码稳定性的前提下对应用程序的内容或功能性进行很小的改动时,最好的做法就是创建装饰器对象

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

$tracksFromExternalSource = ['What It Means','Brr','Goodbye'];

$myCD = new CD();

foreach($tracksFromExternalSource as $track){
    $myCD->addTrack($track);
}

print "The CD contains".$myCD->getTrackList();

//更改需求,要求输出的内容全部大写

class CDTrackListDecoratorCaps{
    private $_cd;
    public function __construct(CD $cd){
        $this->_cd = $cd;
    }
    public function makeCaps(){
        foreach($this->_cd->trackList as &$strack){
            $track = strtoupper($track);
        }
    }
}

$myCD = new CD();

foreach($tracksFromExternalSource as $track){
    $myCD->addTrack($track);
}

$myCDCaps = new CDTrackListDecoratorCaps($myCD);
$myCDCaps->makeCaps();

print "The CD contains the following tracks: ".$myCD->getTrackList();

委托模式

通过分配或委托至其他对象,委托设计模式能够去除核心对象中的判决和复杂的功能性

class Playlist{
    private $_songs;
    public function __construct(){
        $this->_songs = [];
    }

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

    public function getM3U(){
        $m3u = "#EXTM#U\n\n";

        foreach($this->_songs as $song){
            $m3u .= "#EXTINF:-1,{$song['title']}\n";
            $m3u .= "{$song['location']}\n";
        }

        return $m3u;
    }

    public function getPLS(){
        $pls = "[playlist]\nNumberOfEntries=".count($this->_songs)."\n\n";

        foreach($this->_songs as $songCount => $song){
            $counter = $songCount + 1;
            $pls .= "File{$counter}={$song['location']}\n";
            $pls .= "Length{$counter}=-1\n\n";
        }

        return $pls;

    }

}

$playlist = new Playlist();
$playlist->addSong('/home/music/brr.mp3','Brr');
$playlist->addSong('/home/music/goodbye.mp3','Goodbye');

if($externalRetrievedType == 'pls'){
    $playlistCountent = $playlist->getPLS();
}else{
    $playlistCountent = $playlist->getM3U();
}


//使用委托模式

class newPlaylist{
    private $_songs;
    private $_typeObject;

    public function __construct($type){
        $this->_songs = [];
        $object = "{$type}Playlist";
        $this->_typeObject = new $object;
    }
    public function addSong($location,$title){
        $song = ['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 .= "Length{$counter}=-1\n\n";
        }

        return $pls;
    }
}

$externalRetrievedType = 'pls';
$playlist = new newPlaylist($externalRetrievedType);
$playlistCountent = $playlist->getPlaylist();

外观模式

通过在必须的逻辑和方法的集合前创建简单的外观接口,外观设计模式隐藏了来自调用对象的复杂性 在程序中包含许多复杂的逻辑步骤和方法调用时,最佳的做法是创建一个机遇外观设计模式的对象

class CD{
    public $tracks = [];
    public $band = '';
    public $title = '';

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

$tracksFromExternalSource = ['What It Means','Brr','Goodbye'];
$title = 'Waste of a Rib';
$band = 'Never Again';

$cd = new CD($title,$band,$tracksFromExternalSource);

//使用外观模式

class CDUpperCase{
    public static function makeString(CD $cd){
        $cd->$type = strtoupper($cd->type);
    }
    public static function makeArray(CD $cd,$type){
        $cd->$type = array_map('strtoupper',$cd->$type);
    }
}
class CDMakeXML{
    public static function create(CD $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);

        $tracks = $doc->createElement('TRACKS');
        $tracks = $root->appendChild($tracks);

        foreach($cd->tracks as $track){
            $track = $doc->createElement('TRACK',$track);
            $track = $tracks->appendChild($track);
        }

        return $doc->saveXML();
    }
}
//错误的使用方式
CDUpperCase::makeString($cd,'title');
CDUpperCase::makeString($cd,'band');
CDUpperCase::makeArray($cd,'tracks');

print CDMakeXML::create($cd);

//正确的使用方式
class WebServiceFacade{
    public static function makeXMLCall(CD $cd){
        CDUpperCase::makeString($cd,'title');
        CDUpperCase::makeString($cd,'band');
        CDUpperCase::makeArray($cd,'tracks');

        $xml = CDMakeXML::create($cd);
        return $xml;
    }
}

print WebServiceFacade::makeXMLCall($cd);

工厂模式

工厂设计模式提供获取某个对象的新实例的一个接口,同时使调用代码避免确定实际实例化基类的步骤

//第一种类型的CD
class CD{
    public $title = '';
    public $band = '';
    public $tracks = [];

    public function __construct(){}

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

//初始化方式
$tracksFromExternalSource = ['What It Means','Brr','Goodbye'];
$title = 'Waste of a Rib';
$band = 'Never Again';

$cd = new CD();
$cd->setTitle($title);
$cd->setBand($band);
foreach($tracksFromExternalSource as $track){
    $cd->addTrack($track);
}


//第二种类型的CD
class enhancedCD{
    public $title = '';
    public $band = '';
    public $tracks = [];

    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;
    }
}

$type = 'enhanced';

$cd = CDFactory::create($type);
$cd->setTitle($title);
$cd->setBand($band);
foreach($tracksFromExternalSource as $track){
    $cd->addTrack($track);
}

解释器模式 (没懂)

解释器设计模式用于分析一个实体的关键元素,并且针对每个原色都提供自己的解释或相应的动作

class User{
    protected $_username = '';
    public function __construct($username){
        $this->_username = $username;
    }
    public function getProfilePage(){
        $profile = "<h2>I like Nerve Again!</h2>";
        $profile .= "I love all of their songs. My favorite CD:<br />";
        $profile .= "{ {myCD.getTitle}}";

        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 getInterpreted(){
        $prefile = $this->_user->getProfilePage();
        if(preg_match_all('/\{\{myCD\.(.*?)\}\}/',$profile,$triggers,PREG_SET_ORDER)){
            $replacements = [];

            foreach($triggers as $trigger){
                $replacements[] = $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([$myCD,$replacement],$profile));
            }
        }
        return $profile;
    }
}

$username = 'test_name';

$user = new User($username);
$interpreter = new userCDInterpreter();
$interpreter->setUser($user);

print "<h1>{$username}'s Profile</h1>";
print $interpreter->getInterpreted();

迭代器模式 (不懂)

迭代器设计模式可帮助构造特定对象,那些对象能够提供单一标准接口循环或迭代任何类型的可计数数据

class CD{
    public $band = '';
    public $title = '';
    public $trackList = [];

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

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

//迭代器类
class CDSearchByBandIterator implements Iterator{
    private $_CDs = [];
    private $_valid = FALSE;

    public function __construct($bandName){
        $db = mysql_connect('localhost','user','pass');
        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";
        $results = mysql_query($sql);

        $cdID = 0;
        $cd = NULL;

        while($result = mysql_fetch_array($results)){
            if($result['id'] !== $cdID){
                if(!is_null($cd)){
                    $this->_CDs[] = $cd;
                }
                $cdID = $result['id'];
                $cd = new CD($result['band'],$result['title']);
            }
            $cd->addTrack($result['tracktitle']);
        }
        $this->_CDs[] = $cd;
    }
    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);
    }
}

中介者模式

中介者设计模式用于开发一个对象,这个对象能够在类似对象相互之间不直接交互的情况下传送或调解对这些对象的集合的修改 处理具有类似属性并且属性需要保持同步的非耦合对象时,最佳的做法是使用基于中介者设计模式的对象

class CD{
    public $band = '';
    public $title = '';

    public function save(){
        var_dump($this);
    }

    public function changeBandName($newName){
        $this->band = $newName;
        $this->save();
    }
}

//中介者模式

class CD{
    public $band = '';
    public $title = '';
    protected $_mediator;

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

    public function changeBandName($newName){
        if(!is_null($this->_mediator)){
            $this->_mediator->change($this,['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(){
        var_dump($this);
    }

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


}

class MusicContrainerMediator{
    protected $_containers = [];

    public function __construct(){
        $this->_containers[] = 'CD';
        $this->_containers[] = 'MP3Archive';
    }

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

        foreach($this->_containers as $container){
            if(!($changedObject instanceof $container)){
                $object = new $container;
                $object->title = $title;
                $object->band = $band;

                foreach($newValue as $key=>$val){
                    $object->$key = $val;
                }

                $object->save();
            }
        }
    }
}

$titleFromDB = 'Waste of a Rib';
$bandFromDB = 'Never Again';

$mediator = new MusicContainerMediator();

$cd = new CD($mediator);
$cd->title = $titleFromDB;
$cd->band = $bandFromDB;

$cd->changeBandName('Maybe Once More');

观察者模式

观察者设计模式能够更便利地创建查看目标对象状态的对象,并且提供与核心对象非耦合的指定功能性

class CD{
    public $title = '';
    public $band = '';
    protected $_observers = [];

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

    public function attachObserver($type,$observer){
        $this->_observers[$type][] = $observer;
    }

    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(CD $cd){
        $activity = "The CD names {$cd->title} by ";
        $activity .= "{$cd->band} was just purchased. ";
        activityStream::addNewItem($activity);
    }
}

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

$title = 'Waste of a Rib';
$band = 'Never Again';
$cd = new CD($title,$band);

$observer = new buyCDNotifyStreamObserver();

$cd->attachObserver('purchased',$observer);
$cd->buy();

原型模式

原型设计模式创建对象的方式是赋值和克隆初始对象或原型,这种方式比创建新实例更为有效

class CD{
    public $band = '';
    public $title = '';
    public $trackList = [];

    public function __construct($id){
        $handle = mysql_connect('localhost','user','pass');
        mysql_select_db('CD',$handle);

        $query = "select band,title from CDS where id = {$id}";

        $results = mysql_query($query,$handle);

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

    public function buy(){
        var_dump($this);
    }
}

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

$externalPurchaseInfoBandID = 12;
$bandMixProto = new MixtapeCD($externalPurchaseInfoBandID);

$externalPurchaseInfo = [];
$externalPurchaseInfo[] = ['brrr','goodbye'];
$externalPurchaseInfo[] = ['what it means','brrr'];

foreach($externalPurchaseInfo as $mixed){
    $cd = clone $bandMixProto;
    $cd->trackList = $mixed;
    $cd->buy();
}

代理模式

代理设计模式构建了透明置于两个不同对象之内的一个对象,从而能够截取或代理这两个对象间的通信或访问

class CD{
    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 CDs 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 .= "'";

        mysql_query($query,$this->_handle);
    }
    protected function _connect(){
        $this->_handle = mysql_connect('localhost','user','pass');
        mysql_select_db('CD',$this->_handle);
    }
}

$externalTitle = 'Waste of a Rib';
$externalBand = 'Never Again';

$cd = new CD($externalTitle,$externalBand);
$cd->buy();

//代理

class DallasNOCCDProxy extends CD{
    protected function _connect(){
        $this->_handle = mysql_connect('dallas','user','pass');
        mysql_select_db('CD');
    }
}

$externalTitle = 'Waste of a Rib';
$externalBand = 'Never Again';

$cd = new DallasNOCCDProxy($externalTitle,$externalBand);
$cd->buy();

单元素模式

通过提供对自身共享实例的访问,单元素设计模式用于限制特定对象只能被创建一次

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','user','pass');
        mysql_select_db('CD',$this->_handle);
    }

    public function updateQuantity($band,$title,$number){
        $query = "update CDs set amount=amount+".intval($number);
        $query .= " where band='".mysql_real_escape_string($band)."'";
        $query .= " and title='".mysql_real_excape_string($title)."'";

        mysql_query($query,$this->_handle);
    }
}

class CD{
    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);
    }
}

$boughtCDs = [];
$boughtCDs[] = ['band'=>'Never Again','Waste of a Rib'];
$boughtCDs[] = ['band'=>'Therapee','Long Road'];

foreach($boughtCDs as $boughtCD){
    $cd = new CD($boughtCD['title'],$boughtCD['band']);
    $cd->buy();
}

策略模式

策略设计模式帮助构建的对象不必自身包含逻辑,而是能够根据需要利用其它对象中的算法

class CD{
    public $title = '';
    public $band = '';
    public function __construct($title,$band){
        $this->title = $title;
        $this->band = $band;
    }
    public function getAsXML(){
        $doc = new DomDocument();
        $root = $doc->createElement('CD');
        $root = $doc->appendChild($root);
        $title = $doc->createElement('TITLE',$this->title);
        $title = $root->appendChild($title);
        $band = $doc->createElement('BAND',$this->band);
        $band = $root->appendChild($band);

        return $doc->saveXML();
    }
}

$externalBand = 'Never Again';
$externalTitle = 'Waste of a Rib';

$cd = new CD($externalTitle,$externalBand);

print $cd->getAsXML();

//策略模式
class CDusesStrategy{
    public $title = '';
    public $band = '';

    protected $_strategy;

    public function __construct($title,$band){
        $this->title = $title;
        $this->band = $band;
    }
    public function setStrategyContest($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',$this->title);
        $title = $root->appendChild($title);
        $band = $doc->createElement('BAND',$this->band);
        $band = $root->appendChild($band);

        return $doc->saveXML();
    }
}

class CDAsJSONStrategy{
    public function get(CDusesStrategy $cd){
        $json = [];
        $json['CD']['title'] = $cd->title;
        $json['CD'];'band'] = $cd->band;

        return $json_encode($json);
    }
}

$cd = new CDusesStrategy($externalTitle,$externalBand);

$cd->setStrategyContext(new CDAsXMLStrategy());
print $cd->get();

$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->oversizedAddition();
    }

    protected function oversizedAddition(){
        return 0;
    }

    abstract protected function taxAddition();
}

class CD extends SaleItemTemplate{
    public $band;
    public $title;

    public function __construct($band,$title,$price){
        $this->band = $band;
        $this->title = $title,
        $this->price = $price;
    }
    protected function taxAddition(){
        return round($this->price*.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 oversizedAddition(){
        return round($this->price*.20,2);
    }
}

$externalTitle = "Waste of a Rib":
$externalBand = "Never Again";
$externalCDPrice = 12.99;
$externalCerealPrice = 90;

$cd = new CD($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: $'.$creal->price;

访问者模式

访问者设计模式构造了包含某个算法的截然不同的对象,在父对象以标准方式使用这些对象时就会将该算法应用于父对象

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

    }
    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" . sdate('r')."\n";

        file_put_contents('/logs/purchases.log',$logline,FILE_APPEND);
    }
}

$externalBand = 'Never Again';
$externalTitle = 'Wate of a Rib';
$externalPrice = 9.99;

$cd = new CD($externalBand,$externalTitle,$externalPrice);
$cd->buy();
$cd->acceptVisitor(new CDVisitorLogPurchase());


class CDVisitorPopulateDiscountList{
    public function visitCD($cd){
        if($cd->price<10){
            $this->_populateDiscountList($cd);
        }
    }
    protected function _populateDiscountList($cd){

    }
}