本文爲翻譯文章php
原文地址:Design Patterns in PHP
若是打算學習PHP的童鞋能夠參考下筆者的編程語言學習知識體系要點列表html
本文主要討論下Web開發中,準確而言,是PHP開發中的相關的設計模式及其應用。有經驗的開發者確定對於設計模式很是熟悉,可是本文主要是針對那些初級的開發者。首先咱們要搞清楚到底什麼是設計模式,設計模式並非一種用來解釋的模式,它們並非像鏈表那樣的常見的數據結構,也不是某種特殊的應用或者框架設計。事實上,設計模式的解釋以下:git
descriptions of communicating objects and classes that are customized to solve a general design problem in a particular context.算法
另外一方面,設計模式提供了一種普遍的可重用的方式來解決咱們平常編程中經常碰見的問題。設計模式並不必定就是一個類庫或者第三方框架,它們更多的表現爲一種思想而且普遍地應用在系統中。它們也表現爲一種模式或者模板,能夠在多個不一樣的場景下用於解決問題。設計模式能夠用於加速開發,而且將不少大的想法或者設計以一種簡單地方式實現。固然,雖然設計模式在開發中頗有做用,可是千萬要避免在不適當的場景誤用它們。編程
目前常見的設計模式主要有23種,根據使用目標的不一樣能夠分爲如下三大類:json
建立模式:用於建立對象從而將某個對象從實現中解耦合。segmentfault
架構模式:用於在不一樣的對象之間構造大的對象結構。設計模式
行爲模式:用於在不一樣的對象之間管理算法、關係以及職責。數據結構
單例模式是最多見的模式之一,在Web應用的開發中,經常用於容許在運行時爲某個特定的類建立一個可訪問的實例。架構
<?php /** * Singleton class */ final class Product { /** * @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 function __construct() { } private function __clone() { } } $firstProduct = Product::getInstance(); $secondProduct = Product::getInstance(); $firstProduct->mix = 'test'; $secondProduct->mix = 'example'; print_r($firstProduct->mix); // example print_r($secondProduct->mix); // example
在不少狀況下,須要爲系統中的多個類建立單例的構造方式,這樣,能夠創建一個通用的抽象父工廠方法:
<?php abstract class FactoryAbstract { protected static $instances = array(); public static function getInstance() { $className = static::getClassName(); if (!(self::$instances[$className] instanceof $className)) { self::$instances[$className] = new $className(); } return self::$instances[$className]; } public static function removeInstance() { $className = static::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(); } } // using: class FirstProduct extends Factory { public $a = []; } class SecondProduct extends FirstProduct { } FirstProduct::getInstance()->a[] = 1; SecondProduct::getInstance()->a[] = 2; FirstProduct::getInstance()->a[] = 3; SecondProduct::getInstance()->a[] = 4; print_r(FirstProduct::getInstance()->a); // array(1, 3) print_r(SecondProduct::getInstance()->a); // array(2, 4)
註冊臺模式並非很常見,它也不是一個典型的建立模式,只是爲了利用靜態方法更方便的存取數據。
<?php /** * Registry class */ class Package { protected static $data = array(); public static function set($key, $value) { self::$data[$key] = $value; } public static function get($key) { return isset(self::$data[$key]) ? self::$data[$key] : null; } final public static function removeObject($key) { if (array_key_exists($key, self::$data)) { unset(self::$data[$key]); } } } Package::set('name', 'Package name'); print_r(Package::get('name')); // Package name
工廠模式是另外一種很是經常使用的模式,正如其名字所示:確實是對象實例的生產工廠。某些意義上,工廠模式提供了通用的方法有助於咱們去獲取對象,而不須要關心其具體的內在的實現。
<?php interface Factory { public function getProduct(); } interface Product { public function getName(); } class FirstFactory implements Factory { public function getProduct() { return new FirstProduct(); } } class SecondFactory implements Factory { public function getProduct() { return new SecondProduct(); } } class FirstProduct implements Product { public function getName() { return 'The first product'; } } class SecondProduct implements Product { public function getName() { return 'Second product'; } } $factory = new FirstFactory(); $firstProduct = $factory->getProduct(); $factory = new SecondFactory(); $secondProduct = $factory->getProduct(); print_r($firstProduct->getName()); // The first product print_r($secondProduct->getName()); // Second product
有些狀況下咱們須要根據不一樣的選擇邏輯提供不一樣的構造工廠,而對於多個工廠而言須要一個統一的抽象工廠:
<?php class Config { public static $factory = 1; } interface Product { public function getName(); } abstract class AbstractFactory { public static function getFactory() { switch (Config::$factory) { case 1: return new FirstFactory(); case 2: return new SecondFactory(); } throw new Exception('Bad config'); } abstract public function getProduct(); } class FirstFactory extends AbstractFactory { public function getProduct() { return new FirstProduct(); } } class FirstProduct implements Product { public function getName() { return 'The product from the first factory'; } } class SecondFactory extends AbstractFactory { public function getProduct() { return new SecondProduct(); } } class SecondProduct implements Product { public function getName() { return 'The product from second factory'; } } $firstProduct = AbstractFactory::getFactory()->getProduct(); Config::$factory = 2; $secondProduct = AbstractFactory::getFactory()->getProduct(); print_r($firstProduct->getName()); // The first product from the first factory print_r($secondProduct->getName()); // Second product from second factory
對象池能夠用於構造而且存放一系列的對象並在須要時獲取調用:
<?php class Product { protected $id; public function __construct($id) { $this->id = $id; } public function getId() { return $this->id; } } class Factory { protected static $products = array(); public static function pushProduct(Product $product) { self::$products[$product->getId()] = $product; } public static function getProduct($id) { return isset(self::$products[$id]) ? self::$products[$id] : null; } public static function removeProduct($id) { if (array_key_exists($id, self::$products)) { unset(self::$products[$id]); } } } Factory::pushProduct(new Product('first')); Factory::pushProduct(new Product('second')); print_r(Factory::getProduct('first')->getId()); // first print_r(Factory::getProduct('second')->getId()); // second
對於某個變量的延遲初始化也是經常被用到的,對於一個類而言每每並不知道它的哪一個功能會被用到,而部分功能每每是僅僅被須要使用一次。
<?php interface Product { public function getName(); } class Factory { protected $firstProduct; protected $secondProduct; public function getFirstProduct() { if (!$this->firstProduct) { $this->firstProduct = new FirstProduct(); } return $this->firstProduct; } public function getSecondProduct() { if (!$this->secondProduct) { $this->secondProduct = new SecondProduct(); } return $this->secondProduct; } } class FirstProduct implements Product { public function getName() { return 'The first product'; } } class SecondProduct implements Product { public function getName() { return 'Second product'; } } $factory = new Factory(); print_r($factory->getFirstProduct()->getName()); // The first product print_r($factory->getSecondProduct()->getName()); // Second product print_r($factory->getFirstProduct()->getName()); // The first product
有些時候,部分對象須要被初始化屢次。而特別是在若是初始化須要耗費大量時間與資源的時候進行預初始化而且存儲下這些對象。
<?php interface Product { } class Factory { private $product; public function __construct(Product $product) { $this->product = $product; } public function getProduct() { return clone $this->product; } } class SomeProduct implements Product { public $name; } $prototypeFactory = new Factory(new SomeProduct()); $firstProduct = $prototypeFactory->getProduct(); $firstProduct->name = 'The first product'; $secondProduct = $prototypeFactory->getProduct(); $secondProduct->name = 'Second product'; print_r($firstProduct->name); // The first product print_r($secondProduct->name); // Second product
構造者模式主要在於建立一些複雜的對象:
<?php class Product { private $name; public function setName($name) { $this->name = $name; } public function getName() { return $this->name; } } abstract class Builder { protected $product; final public function getProduct() { return $this->product; } public function buildProduct() { $this->product = new Product(); } } class FirstBuilder extends Builder { public function buildProduct() { parent::buildProduct(); $this->product->setName('The product of the first builder'); } } class SecondBuilder extends Builder { public function buildProduct() { parent::buildProduct(); $this->product->setName('The product of second builder'); } } class Factory { private $builder; public function __construct(Builder $builder) { $this->builder = $builder; $this->builder->buildProduct(); } public function getProduct() { return $this->builder->getProduct(); } } $firstDirector = new Factory(new FirstBuilder()); $secondDirector = new Factory(new SecondBuilder()); print_r($firstDirector->getProduct()->getName()); // The product of the first builder print_r($secondDirector->getProduct()->getName()); // The product of second builder
裝飾器模式容許咱們根據運行時不一樣的情景動態地爲某個對象調用先後添加不一樣的行爲動做。
<?php class HtmlTemplate { // any parent class methods } class Template1 extends HtmlTemplate { protected $_html; public function __construct() { $this->_html = "<p>__text__</p>"; } public function set($html) { $this->_html = $html; } public function render() { echo $this->_html; } } class Template2 extends HtmlTemplate { protected $_element; public function __construct($s) { $this->_element = $s; $this->set("<h2>" . $this->_html . "</h2>"); } public function __call($name, $args) { $this->_element->$name($args[0]); } } class Template3 extends HtmlTemplate { protected $_element; public function __construct($s) { $this->_element = $s; $this->set("<u>" . $this->_html . "</u>"); } public function __call($name, $args) { $this->_element->$name($args[0]); } }
這種模式容許使用不一樣的接口重構某個類,能夠容許使用不一樣的調用方式進行調用:
<?php class SimpleBook { private $author; private $title; function __construct($author_in, $title_in) { $this->author = $author_in; $this->title = $title_in; } function getAuthor() { return $this->author; } function getTitle() { return $this->title; } } class BookAdapter { private $book; function __construct(SimpleBook $book_in) { $this->book = $book_in; } function getAuthorAndTitle() { return $this->book->getTitle().' by '.$this->book->getAuthor(); } } // Usage $book = new SimpleBook("Gamma, Helm, Johnson, and Vlissides", "Design Patterns"); $bookAdapter = new BookAdapter($book); echo 'Author and Title: '.$bookAdapter->getAuthorAndTitle(); function echo $line_in) { echo $line_in."<br/>"; }
測試模式主要爲了讓客戶類可以更好地使用某些算法而不須要知道其具體的實現。
<?php interface OutputInterface { public function load(); } class SerializedArrayOutput implements OutputInterface { public function load() { return serialize($arrayOfData); } } class JsonStringOutput implements OutputInterface { public function load() { return json_encode($arrayOfData); } } class ArrayOutput implements OutputInterface { public function load() { return $arrayOfData; } }
某個對象能夠被設置爲是可觀察的,只要經過某種方式容許其餘對象註冊爲觀察者。每當被觀察的對象改變時,會發送信息給觀察者。
<?php interface Observer { function onChanged($sender, $args); } interface Observable { function addObserver($observer); } class CustomerList implements Observable { private $_observers = array(); public function addCustomer($name) { foreach($this->_observers as $obs) $obs->onChanged($this, $name); } public function addObserver($observer) { $this->_observers []= $observer; } } class CustomerListLogger implements Observer { public function onChanged($sender, $args) { echo( "'$args' Customer has been added to the list \n" ); } } $ul = new UserList(); $ul->addObserver( new CustomerListLogger() ); $ul->addCustomer( "Jack" );
這種模式有另外一種稱呼:控制鏈模式。它主要由一系列對於某些命令的處理器構成,每一個查詢會在處理器構成的責任鏈中傳遞,在每一個交匯點由處理器判斷是否須要對它們進行響應與處理。每次的處理程序會在有處理器處理這些請求時暫停。
<?php interface Command { function onCommand($name, $args); } class CommandChain { private $_commands = array(); public function addCommand($cmd) { $this->_commands[]= $cmd; } public function runCommand($name, $args) { foreach($this->_commands as $cmd) { if ($cmd->onCommand($name, $args)) return; } } } class CustCommand implements Command { public function onCommand($name, $args) { if ($name != 'addCustomer') return false; echo("This is CustomerCommand handling 'addCustomer'\n"); return true; } } class MailCommand implements Command { public function onCommand($name, $args) { if ($name != 'mail') return false; echo("This is MailCommand handling 'mail'\n"); return true; } } $cc = new CommandChain(); $cc->addCommand( new CustCommand()); $cc->addCommand( new MailCommand()); $cc->runCommand('addCustomer', null); $cc->runCommand('mail', null);