設計模式:提供了一種普遍的可重用的方式來解決咱們平常編程中經常碰見的問題。設計模式並不必定就是一個類庫或者第三方框架,它們更多的表現爲一種思想而且普遍地應用在系統中。它們也表現爲一種模式或者模板,能夠在多個不一樣的場景下用於解決問題。設計模式能夠用於加速開發,而且將不少大的想法或者設計以一種簡單地方式實現。固然,雖然設計模式在開發中頗有做用,可是千萬要避免在不適當的場景誤用它們。php
根據目的和範圍,設計模式能夠分爲五類。
按照目的分爲:建立設計模式,結構設計模式,以及行爲設計模式。
按照範圍分爲:類的設計模式,以及對象設計模式。算法
1. 按照目的分,目前常見的設計模式主要有23種,根據使用目標的不一樣能夠分爲如下三大類:sql
建立設計模式(Creational Patterns)(5種):用於建立對象時的設計模式。更具體一點,初始化對象流程的設計模式。當程序日益複雜時,須要更加靈活地建立對象,同時減小建立時的依賴。而建立設計模式就是解決此問題的一類設計模式。express
結構設計模式(Structural Patterns)(7種):用於繼承和接口時的設計模式。結構設計模式用於新類的函數方法設計,減小沒必要要的類定義,減小代碼的冗餘。編程
行爲模式(Behavioral Patterns)(11種):用於方法實現以及對應算法的設計模式,同時也是最複雜的設計模式。行爲設計模式不只僅用於定義類的函數行爲,同時也用於不一樣類之間的協議、通訊。設計模式
2.按照範圍分爲:類的設計模式,以及對象設計模式數組
類的設計模式(Class patterns):用於類的具體實現的設計模式。包含了如何設計和定義類,以及父類和子類的設計模式。安全
對象設計模式(Object patterns): 用於對象的設計模式。與類的設計模式不一樣,對象設計模式主要用於運行期對象的狀態改變、動態行爲變動等。網絡
- 開放封閉原則:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。
- 里氏替換原則:全部引用基類的地方必須能透明地使用其子類的對象.
- 依賴倒置原則:高層模塊不該該依賴低層模塊,兩者都應該依賴其抽象;抽象不該該依賴細節;細節應該依賴抽象。
- 單一職責原則:不要存在多於一個致使類變動的緣由。通俗的說,即一個類只負責一項職責。
- 接口隔離原則:客戶端不該該依賴它不須要的接口;一個類對另外一個類的依賴應該創建在最小的接口上。
- 迪米特法則:一個對象應該對其餘對象保持最少的瞭解。
<?php /** * Singleton class[單例模式] * @author ITYangs<ityangs@163.com> */ final class Mysql { /** * * @var self[該屬性用來保存實例] */ private static $instance; /** * * @var mixed */ public $mix; /** * Return self instance[建立一個用來實例化對象的方法] * * @return self */ public static function getInstance() { if (! (self::$instance instanceof self)) { self::$instance = new self(); } return self::$instance; } /** * 構造函數爲private,防止建立對象 */ private function __construct() {} /** * 防止對象被複制 */ private function __clone() { trigger_error('Clone is not allowed !'); } } // @test $firstMysql = Mysql::getInstance(); $secondMysql = Mysql::getInstance(); $firstMysql->mix = 'ityangs_one'; $secondMysql->mix = 'ityangs_two'; print_r($firstMysql->mix); // 輸出: ityangs_two print_r($secondMysql->mix); // 輸出: ityangs_two
在不少狀況下,須要爲系統中的多個類建立單例的構造方式,這樣,能夠創建一個通用的抽象父工廠方法:架構
<?php /** * Singleton class[單例模式:多個類建立單例的構造方式] * @author ITYangs<ityangs@163.com> */ abstract class FactoryAbstract { protected static $instances = array(); public static function getInstance() { $className = self::getClassName(); if (!(self::$instances[$className] instanceof $className)) { self::$instances[$className] = new $className(); } return self::$instances[$className]; } public static function removeInstance() { $className = self::getClassName(); if (array_key_exists($className, self::$instances)) { unset(self::$instances[$className]); } } final protected static function getClassName() { return get_called_class(); } protected function __construct() { } final protected function __clone() { } } abstract class Factory extends FactoryAbstract { final public static function getInstance() { return parent::getInstance(); } final public static function removeInstance() { parent::removeInstance(); } } // @test class FirstProduct extends Factory { public $a = []; } class SecondProduct extends FirstProduct { } FirstProduct::getInstance()->a[] = 1; SecondProduct::getInstance()->a[] = 2; FirstProduct::getInstance()->a[] = 11; SecondProduct::getInstance()->a[] = 22; print_r(FirstProduct::getInstance()->a); // Array ( [0] => 1 [1] => 11 ) print_r(SecondProduct::getInstance()->a); // Array ( [0] => 2 [1] => 22 )
工廠模式是另外一種很是經常使用的模式,正如其名字所示:確實是對象實例的生產工廠。某些意義上,工廠模式提供了通用的方法有助於咱們去獲取對象,而不須要關心其具體的內在的實現。
<?php /** * Factory class[工廠模式] * @author ITYangs<ityangs@163.com> */ interface SystemFactory { public function createSystem($type); } class MySystemFactory implements SystemFactory { // 實現工廠方法 public function createSystem($type) { switch ($type) { case 'Mac': return new MacSystem(); case 'Win': return new WinSystem(); case 'Linux': return new LinuxSystem(); } } } class System{ /* ... */} class WinSystem extends System{ /* ... */} class MacSystem extends System{ /* ... */} class LinuxSystem extends System{ /* ... */} //建立個人系統工廠 $System_obj = new MySystemFactory(); //用個人系統工廠分別建立不一樣系統對象 var_dump($System_obj->createSystem('Mac'));//輸出:object(MacSystem)#2 (0) { } var_dump($System_obj->createSystem('Win'));//輸出:object(WinSystem)#2 (0) { } var_dump($System_obj->createSystem('Linux'));//輸出:object(LinuxSystem)#2 (0) { }
有些狀況下咱們須要根據不一樣的選擇邏輯提供不一樣的構造工廠,而對於多個工廠而言須要一個統一的抽象工廠:
<?php class System{} class Soft{} class MacSystem extends System{} class MacSoft extends Soft{} class WinSystem extends System{} class WinSoft extends Soft{} /** * AbstractFactory class[抽象工廠模式] * @author ITYangs<ityangs@163.com> */ interface AbstractFactory { public function CreateSystem(); public function CreateSoft(); } class MacFactory implements AbstractFactory{ public function CreateSystem(){ return new MacSystem(); } public function CreateSoft(){ return new MacSoft(); } } class WinFactory implements AbstractFactory{ public function CreateSystem(){ return new WinSystem(); } public function CreateSoft(){ return new WinSoft(); } } //@test:建立工廠->用該工廠生產對應的對象 //建立MacFactory工廠 $MacFactory_obj = new MacFactory(); //用MacFactory工廠分別建立不一樣對象 var_dump($MacFactory_obj->CreateSystem());//輸出:object(MacSystem)#2 (0) { } var_dump($MacFactory_obj->CreateSoft());// 輸出:object(MacSoft)#2 (0) { } //建立WinFactory $WinFactory_obj = new WinFactory(); //用WinFactory工廠分別建立不一樣對象 var_dump($WinFactory_obj->CreateSystem());//輸出:object(WinSystem)#3 (0) { } var_dump($WinFactory_obj->CreateSoft());//輸出:object(WinSoft)#3 (0) { }
建造者模式主要在於建立一些複雜的對象。將一個複雜對象的構造與它的表示分離,使一樣的構建過程能夠建立不一樣的表示的設計模式;
結構圖:
<?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(); echo "<pre>"; var_dump($product); echo "</pre>"; /*輸出: object(Product)#2 (1) { ["_parts":"Product":private]=> array(2) { [0]=>string(5) "Part1" [1]=>string(5) "Part2" } } */ ?>
有時候,部分對象須要被初始化屢次。而特別是在若是初始化須要耗費大量時間與資源的時候進行預初始化而且存儲下這些對象,就會用到原型模式:
<?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 Test {} // client $object1 = new ConcretePrototype(new Test()); var_dump($object1);//輸出:object(ConcretePrototype)#1 (1) { ["_name":"ConcretePrototype":private]=> object(Test)#2 (0) { } } $object2 = $object1->copy(); var_dump($object2);//輸出:object(ConcretePrototype)#3 (1) { ["_name":"ConcretePrototype":private]=> object(Test)#2 (0) { } } ?>
這種模式容許使用不一樣的接口重構某個類,能夠容許使用不一樣的調用方式進行調用:
<?php /** * 第一種方式:對象適配器 */ interface Target { public function sampleMethod1(); public function sampleMethod2(); } class Adaptee { public function sampleMethod1() { echo '++++++++'; } } class Adapter implements Target { private $_adaptee; public function __construct(Adaptee $adaptee) { $this->_adaptee = $adaptee; } public function sampleMethod1() { $this->_adaptee->sampleMethod1(); } public function sampleMethod2() { echo '————————'; } } $adapter = new Adapter(new Adaptee()); $adapter->sampleMethod1();//輸出:++++++++ $adapter->sampleMethod2();//輸出:———————— /** * 第二種方式:類適配器 */ interface Target2 { public function sampleMethod1(); public function sampleMethod2(); } class Adaptee2 { // 源角色 public function sampleMethod1() {echo '++++++++';} } class Adapter2 extends Adaptee2 implements Target2 { // 適配后角色 public function sampleMethod2() {echo '————————';} } $adapter = new Adapter2(); $adapter->sampleMethod1();//輸出:++++++++ $adapter->sampleMethod2();//輸出:———————— ?>
將抽象部分與它的實現部分分離,使他們均可以獨立的變抽象與它的實現分離,即抽象類和它的派生類用來實現本身的對象
橋接與適配器模式的關係(適配器模式上面已講解):
橋接屬於聚合關係,二者關聯 但不繼承
適配器屬於組合關係,適配者須要繼承源
聚合關係:A對象能夠包含B對象 但B對象不是A對象的一部分
<?php /** * *實現化角色, 給出實現化角色的接口,但不給出具體的實現。 */ abstract class Implementor { abstract public function operationImp(); } class ConcreteImplementorA extends Implementor { // 具體化角色A public function operationImp() {echo "A";} } class ConcreteImplementorB extends Implementor { // 具體化角色B public function operationImp() {echo "B";} } /** * * 抽象化角色,抽象化給出的定義,並保存一個對實現化對象的引用 */ 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(); } } // client $abstraction = new RefinedAbstraction(new ConcreteImplementorA()); $abstraction->operation();//輸出:A $abstraction = new RefinedAbstraction(new ConcreteImplementorB()); $abstraction->operation();//輸出:B ?>
組合模式(Composite Pattern)有時候又叫作部分-總體模式,用於將對象組合成樹形結構以表示「部分-總體」的層次關係。組合模式使得用戶對單個對象和組合對象的使用具備一致性。
常見使用場景:如樹形菜單、文件夾菜單、部門組織架構圖等。
<?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(); /** * *透明式合成模式 */ 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() {echo $this->_name."<br>";} 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(); ?>
裝飾器模式容許咱們根據運行時不一樣的情景動態地爲某個對象調用先後添加不一樣的行
<?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() {echo 'A加點醬油;';} } class ConcreteDecoratorB extends Decorator { // 具體裝飾類B public function __construct(Component $component) { parent::__construct($component); } public function operation() { parent::operation(); $this->addedOperationB(); } public function addedOperationB() {echo "B加點辣椒;";} } class ConcreteComponent implements Component{ //具體組件類 public function operation() {} } // clients $component = new ConcreteComponent(); $decoratorA = new ConcreteDecoratorA($component); $decoratorB = new ConcreteDecoratorB($decoratorA); $decoratorA->operation();//輸出:A加點醬油; echo '<br>--------<br>'; $decoratorB->operation();//輸出:A加點醬油;B加點辣椒; ?>
門面模式 (Facade)又稱外觀模式,用於爲子系統中的一組接口提供一個一致的界面。門面模式定義了一個高層接口,這個接口使得子系統更加容易使用:引入門面角色以後,用戶只須要直接與門面角色交互,用戶與子系統之間的複雜關係由門面角色來實現,從而下降了系統的耦
<?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(); ?>
代理模式(Proxy)爲其餘對象提供一種代理以控制對這個對象的訪問。使用代理模式建立代理對象,讓代理對象控制目標對象的訪問(目標對象能夠是遠程的對象、建立開銷大的對象或須要安全控制的對象),而且能夠在不改變目標對象的狀況下添加一些額外的功能。
在某些狀況下,一個客戶不想或者不能直接引用另外一個對象,而代理對象能夠在客戶端和目標對象之間起到中介的做用,而且能夠經過代理對象去掉客戶不能看到的內容和服務或者添加客戶須要的額外服務。
經典例子就是網絡代理,你想訪問 Facebook 或者 Twitter ,如何繞過 GFW?找個代理
<? 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() { echo '在action前,我想幹點啥....'; } private function _afterAction() { echo '在action後,我還想幹點啥....'; } } // client $subject = new ProxySubject(); $subject->action();//輸出:在action前,我想幹點啥....在action後,我還想幹點啥.... ?>
運用共享技術有效的支持大量細粒度的對象
享元模式變化的是對象的存儲開銷
享元模式中主要角色:
抽象享元(Flyweight)角色:此角色是全部的具體享元類的超類,爲這些類規定出須要實現的公共接口。那些須要外運狀態的操做能夠經過調用商業以參數形式傳入
具體享元(ConcreteFlyweight)角色:實現Flyweight接口,併爲內部狀態(若是有的話)拉回存儲空間。ConcreteFlyweight對象必須是可共享的。它所存儲的狀態必須是內部的
不共享的具體享元(UnsharedConcreteFlyweight)角色:並不是全部的Flyweight子類都須要被共享。Flyweigth使共享成爲可能,但它並不強制共享
享元工廠(FlyweightFactory)角色:負責建立和管理享元角色。本角色必須保證享元對象可能被系統適當地共享
客戶端(Client)角色:本角色須要維護一個對全部享元對象的引用。本角色須要自行存儲全部享元對象的外部狀態
享元模式的優勢:
Flyweight模式能夠大幅度地下降內存中對象的數量
享元模式的缺點:
Flyweight模式使得系統更加複雜
Flyweight模式將享元對象的狀態外部化,而讀取外部狀態使得運行時間稍微變長
享元模式適用場景:
當一下狀況成立時使用Flyweight模式:
1 一個應用程序使用了大量的對象
2 徹底因爲使用大量的對象,形成很大的存儲開銷
3 對象的大多數狀態均可變爲外部狀態
4 若是刪除對象的外部狀態,那麼能夠用相對較少的共享對象取代不少組對象
5 應用程序不依賴於對象標識
<?php abstract class Resources{ public $resource=null; abstract public function operate(); } class unShareFlyWeight extends Resources{ public function __construct($resource_str) { $this->resource = $resource_str; } public function operate(){ echo $this->resource."<br>"; } } class shareFlyWeight extends Resources{ private $resources = array(); public function get_resource($resource_str){ if(isset($this->resources[$resource_str])) { return $this->resources[$resource_str]; }else { return $this->resources[$resource_str] = $resource_str; } } public function operate(){ foreach ($this->resources as $key => $resources) { echo $key.":".$resources."<br>"; } } } // client $flyweight = new shareFlyWeight(); $flyweight->get_resource('a'); $flyweight->operate(); $flyweight->get_resource('b'); $flyweight->operate(); $flyweight->get_resource('c'); $flyweight->operate(); // 不共享的對象,單獨調用 $uflyweight = new unShareFlyWeight('A'); $uflyweight->operate(); $uflyweight = new unShareFlyWeight('B'); $uflyweight->operate(); /* 輸出: a:a a:a b:b a:a b:b c:c A B */
策略模式主要爲了讓客戶類可以更好地使用某些算法而不須要知道其具體的實現。
<?php interface Strategy { // 抽象策略角色,以接口實現 public function do_method(); // 算法接口 } class ConcreteStrategyA implements Strategy { // 具體策略角色A public function do_method() { echo 'do method A'; } } class ConcreteStrategyB implements Strategy { // 具體策略角色B public function do_method() { echo 'do method B'; } } class ConcreteStrategyC implements Strategy { // 具體策略角色C public function do_method() { echo 'do method C'; } } class Question{ // 環境角色 private $_strategy; public function __construct(Strategy $strategy) { $this->_strategy = $strategy; } public function handle_question() { $this->_strategy->do_method(); } } // client $strategyA = new ConcreteStrategyA(); $question = new Question($strategyA); $question->handle_question();//輸出do method A $strategyB = new ConcreteStrategyB(); $question = new Question($strategyB); $question->handle_question();//輸出do method B $strategyC = new ConcreteStrategyC(); $question = new Question($strategyC); $question->handle_question();//輸出do method C ?>
模板模式準備一個抽象類,將部分邏輯以具體方法以及具體構造形式實現,而後聲明一些抽象方法來迫使子類實現剩餘的邏輯。不一樣的子類能夠以不一樣的方式實現這些抽象方法,從而對剩餘的邏輯有不一樣的實現。先制定一個頂級邏輯框架,而將邏輯的細節留給具體的子類去實現。
<?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(); ?>
某個對象能夠被設置爲是可觀察的,只要經過某種方式容許其餘對象註冊爲觀察者。每當被觀察的對象改變時,會發送信息給觀察者。
<?php interface IObserver{ function onSendMsg( $sender, $args ); function getName(); } interface IObservable{ function addObserver( $observer ); } class UserList implements IObservable{ private $_observers = array(); public function sendMsg( $name ){ foreach( $this->_observers as $obs ){ $obs->onSendMsg( $this, $name ); } } public function addObserver( $observer ){ $this->_observers[]= $observer; } public function removeObserver($observer_name) { foreach($this->_observers as $index => $observer) { if ($observer->getName() === $observer_name) { array_splice($this->_observers, $index, 1); return; } } } } class UserListLogger implements IObserver{ public function onSendMsg( $sender, $args ){ echo( "'$args' send to UserListLogger\n" ); } public function getName(){ return 'UserListLogger'; } } class OtherObserver implements IObserver{ public function onSendMsg( $sender, $args ){ echo( "'$args' send to OtherObserver\n" ); } public function getName(){ return 'OtherObserver'; } } $ul = new UserList();//被觀察者 $ul->addObserver( new UserListLogger() );//增長觀察者 $ul->addObserver( new OtherObserver() );//增長觀察者 $ul->sendMsg( "Jack" );//發送消息到觀察者 $ul->removeObserver('UserListLogger');//移除觀察者 $ul->sendMsg("hello");//發送消息到觀察者 /* 輸出:'Jack' send to UserListLogger 'Jack' send to OtherObserver 'hello' send to OtherObserver */ ?>
迭代器模式 (Iterator),又叫作遊標(Cursor)模式。提供一種方法訪問一個容器(Container)對象中各個元素,而又不需暴露該對象的內部細節。
當你須要訪問一個聚合對象,並且無論這些對象是什麼都須要遍歷的時候,就應該考慮使用迭代器模式。另外,當須要對彙集有多種方式遍歷時,能夠考慮去使用迭代器模式。迭代器模式爲遍歷不一樣的彙集結構提供如開始、下一個、是否結束、當前哪一項等統一的接口。
php標準庫(SPL)中提供了迭代器接口 Iterator,要實現迭代器模式,實現該接口便可。
<?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 />'; } /* 輸出: 0 1 1 2 2 3 3 4 4 5 */ //Yii FrameWork Demo class CMapIterator implements Iterator { /** * @var array the data to be iterated through */ private $_d; /** * @var array list of keys in the map */ private $_keys; /** * @var mixed current key */ private $_key; /** * Constructor. * @param array the data to be iterated through */ public function __construct(&$data) { $this->_d=&$data; $this->_keys=array_keys($data); } /** * Rewinds internal array pointer. * This method is required by the interface Iterator. */ public function rewind() { $this->_key=reset($this->_keys); } /** * Returns the key of the current array element. * This method is required by the interface Iterator. * @return mixed the key of the current array element */ public function key() { return $this->_key; } /** * Returns the current array element. * This method is required by the interface Iterator. * @return mixed the current array element */ public function current() { return $this->_d[$this->_key]; } /** * Moves the internal pointer to the next array element. * This method is required by the interface Iterator. */ public function next() { $this->_key=next($this->_keys); } /** * Returns whether there is an element at current position. * This method is required by the interface Iterator. * @return boolean */ public function valid() { return $this->_key!==false; } } $data = array('s1' => 11, 's2' => 22, 's3' => 33); $it = new CMapIterator($data); foreach ($it as $row) { echo $row, '<br />'; } /* 輸出: 11 22 33 */ ?>
這種模式有另外一種稱呼:控制鏈模式。它主要由一系列對於某些命令的處理器構成,每一個查詢會在處理器構成的責任鏈中傳遞,在每一個交匯點由處理器判斷是否須要對它們進行響應與處理。每次的處理程序會在有處理器處理這些請求時暫停。
<?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(); echo 'Res_A start'."<br>"; } } } class ResponsibilityB extends Responsibility { public function __construct() {} public function operate(){ if (false == is_null($this->next)) { $this->next->operate(); echo 'Res_B start'; } } } $res_a = new ResponsibilityA(); $res_b = new ResponsibilityB(); $res_a->setNext($res_b); $res_a->operate();//輸出:Res_A start ?>
命令模式:在軟件系統中,「行爲請求者」與「行爲實現者」一般呈現一種「緊耦合」。但在某些場合,好比要對行爲進行「記錄、撤銷/重作、事務」等處理,這種沒法抵禦變化的緊耦合是不合適的。在這種狀況下,如何將「行爲請求者」與「行爲實現者」解耦?將一組行爲抽象爲對象,實現兩者之間的鬆耦合。這就是命令模式。
角色分析:
抽象命令:定義命令的接口,聲明執行的方法。
具體命令:命令接口實現對象,是「虛」的實現;一般會持有接收者,並調用接收者的功能來完成命令要執行的操做。
命令接收者:接收者,真正執行命令的對象。任何類均可能成爲一個接收者,只要它可以實現命令要求實現的相應功能。
控制者:要求命令對象執行請求,一般會持有命令對象,能夠持有不少的命令對象。這個是客戶端真正觸發命令並要求命令執行相應操做的地方,也就是說至關於使用命令對象的入口。
<?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() { echo 'receive some cmd:'.$this->_name; } } 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();//輸出:receive some cmd:hello world ?>
備忘錄模式又叫作快照模式(Snapshot)或 Token 模式,備忘錄模式的用意是在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態,這樣就能夠在合適的時候將該對象恢復到原先保存的狀態。
咱們在編程的時候,常常須要保存對象的中間狀態,當須要的時候,能夠恢復到這個狀態。好比,咱們使用Eclipse進行編程時,假如編寫失誤(例如不當心誤刪除了幾行代碼),咱們但願返回刪除前的狀態,即可以使用Ctrl+Z來進行返回。這時咱們即可以使用備忘錄模式來實現。
UML:
備忘錄模式所涉及的角色有三個:備忘錄(Memento)角色、發起人(Originator)角色、負責人(Caretaker)角色。
這三個角色的職責分別是:
發起人:記錄當前時刻的內部狀態,負責定義哪些屬於備份範圍的狀態,負責建立和恢復備忘錄數據。
備忘錄:負責存儲發起人對象的內部狀態,在須要的時候提供發起人須要的內部狀態。
管理角色:對備忘錄進行管理,保存和提供備忘錄。
<?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() { echo $this->_state;echo "<br>"; } } 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($memento); $org->showState(); /* 改變目標對象的狀態 */ $org->setState('close'); $org->showState(); /* 還原操做 */ $org->restoreMemento($caretaker->getMemento()); $org->showState(); /* 輸出: open close open close open */ ?>
狀態模式當一個對象的內在狀態改變時容許改變其行爲,這個對象看起來像是改變了其類。狀態模式主要解決的是當控制一個對象狀態的條件表達式過於複雜時的狀況。把狀態的判斷邏輯轉移到表示不一樣狀態的一系列類中,能夠把複雜的判斷邏輯簡化。
UML類圖:
角色:
上下文環境(Work):它定義了客戶程序須要的接口並維護一個具體狀態角色的實例,將與狀態相關的操做委託給當前的具體對象來處理。
抽象狀態(State):定義一個接口以封裝使用上下文環境的的一個特定狀態相關的行爲。
具體狀態(AmState):實現抽象狀態定義的接口。
<?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) { echo 'concrete_a'."<br>"; $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) { echo 'concrete_b'."<br>"; $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(); /* 輸出: concrete_a concrete_b concrete_a concrete_b */ ?>
訪問者模式是一種行爲型模式,訪問者表示一個做用於某對象結構中各元素的操做。它能夠在不修改各元素類的前提下定義做用於這些元素的新操做,即動態的增長具體訪問者角色。
訪問者模式利用了雙重分派。先將訪問者傳入元素對象的Accept方法中,而後元素對象再將本身傳入訪問者,以後訪問者執行元素的相應方法。
主要角色
抽象訪問者角色(Visitor):爲該對象結構(ObjectStructure)中的每個具體元素提供一個訪問操做接口。該操做接口的名字和參數標識了 要訪問的具體元素角色。這樣訪問者就能夠經過該元素角色的特定接口直接訪問它。
具體訪問者角色(ConcreteVisitor):實現抽象訪問者角色接口中針對各個具體元素角色聲明的操做。
抽象節點(Node)角色:該接口定義一個accept操做接受具體的訪問者。
具體節點(Node)角色:實現抽象節點角色中的accept操做。
對象結構角色(ObjectStructure):這是使用訪問者模式必備的角色。它要具有如下特徵:能枚舉它的元素;能夠提供一個高層的接口以容許該訪問者訪問它的元素;能夠是一個複合(組合模式)或是一個集合,如一個列表或一個無序集合(在PHP中咱們使用數組代替,由於PHP中的數組原本就是一個能夠放置任何類型數據的集合)
適用性
訪問者模式多用在彙集類型多樣的狀況下。在普通的形式下必須判斷每一個元素是屬於什麼類型而後進行相應的操做,從而誕生出冗長的條件轉移語句。而訪問者模式則能夠比較好的解決這個問題。對每一個元素統一調用element−>accept(vistor)便可。
訪問者模式多用於被訪問的類結構比較穩定的狀況下,即不會隨便添加子類。訪問者模式容許被訪問結構添加新的方法。
<?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); ?>
中介者模式用於開發一個對象,這個對象可以在相似對象相互之間不直接相互的狀況下傳送或者調解對這些對象的集合的修改。 通常處理具備相似屬性,須要保持同步的非耦合對象時,最佳的作法就是中介者模式。PHP中不是特別經常使用的設計模式。
<?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) { //echo $colleague->notify($message); 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) { echo 'colleague1:'.$message."<br>"; } } class Colleague2 extends Colleague { // 具體對象角色 public function notify($message) { echo 'colleague2:'.$message."<br>"; } } // client $objMediator = new ConcreteMediator(); $objC1 = new Colleague1($objMediator); $objC2 = new Colleague2($objMediator); $objMediator->set($objC1,$objC2); $objC1->send("to c2 from c1"); //輸出:colleague1:to c2 from c1 $objC2->send("to c1 from c2"); //輸出:colleague2:to c1 from c2 ?>
給定一個語言, 定義它的文法的一種表示,並定義一個解釋器,該解釋器使用該表示來解釋語言中的句子。
角色:
環境角色(PlayContent):定義解釋規則的全局信息。
抽象解釋器(Empress):定義了部分解釋具體實現,封裝了一些由具體解釋器實現的接口。
具體解釋器(MusicNote):實現抽象解釋器的接口,進行具體的解釋執行。
<?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); echo "<br>"; } } } //client $obj = new Interpreter(); $obj->execute("123s45abc"); /* 輸出: 一 二 三 S 四 五 A B C */ ?>