??> 原文地址:
Design Patterns in PHP
本文主要討論下Web開發中,準確而言,是PHP開發中的相關的設計模式及其應用。有經驗的開發人員肯定對於設計模式非常熟悉,但是本文主要是針對那些初級的開發人員。首先我們要搞清楚到底什麼是設計模式,設計模式並不是一種用來解釋的模式,它們並不是像鏈表那樣的常見的資料結構,也不是某種特殊的應用或者架構設計。事實上,設計模式的解釋如下:
descriptions of communicating objects and classes that are customized to solve a general design problem in a particular context.
另一方面,設計模式提供了一種廣泛的可重用的方式來解決我們日常編程中常常遇見的問題。設計模式並不一定就是一個類庫或者第三方架構,它們更多的表現為一種思想並且廣泛地應用在系統中。它們也表現為一種模式或者模板,可以在多個不同的情境下用於解決問題。設計模式可以用於加速開發,並且將很多大的想法或者設計以一種簡單地方式實現。當然,雖然設計模式在開發中很有作用,但是千萬要避免在不適當的情境誤用它們。
目前常見的設計模式主要有23種,根據使用目標的不同可以分為以下三大類:
Creational Patterns
Singleton(單例模式)
單例模式是最常見的模式之一,在Web應用的開發中,常常用於允許在運行時為某個特定的類建立一個可訪問的執行個體。
mix = 'test';$secondProduct->mix = 'example';print_r($firstProduct->mix);// exampleprint_r($secondProduct->mix);// example
在很多情況下,需要為系統中的多個類建立單例的構造方式,這樣,可以建立一個通用的抽象父Factory 方法:
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)
Registry
註冊台模式並不是很常見,它也不是一個典型的建立模式,只是為了利用靜態方法更方便的存取資料。
Factory(原廠模式)
原廠模式是另一種非常常用的模式,正如其名字所示:確實是對象執行個體的生產工廠。某些意義上,原廠模式提供了通用的方法有助於我們去擷取對象,而不需要關心其具體的內在的實現。
getProduct();$factory = new SecondFactory();$secondProduct = $factory->getProduct();print_r($firstProduct->getName());// The first productprint_r($secondProduct->getName());// Second product
AbstractFactory(抽象原廠模式)
有些情況下我們需要根據不同的選擇邏輯提供不同的構造工廠,而對於多個工廠而言需要一個統一的抽象工廠:
getProduct();Config::$factory = 2;$secondProduct = AbstractFactory::getFactory()->getProduct();print_r($firstProduct->getName());// The first product from the first factoryprint_r($secondProduct->getName());// Second product from second factory
Object pool(對象池)
對象池可以用於構造並且存放一系列的對象並在需要時擷取調用:
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());// firstprint_r(Factory::getProduct('second')->getId());// second Lazy Initialization(延遲初始化)
對於某個變數的延遲初始化也是常常被用到的,對於一個類而言往往並不知道它的哪個功能會被用到,而部分功能往往是僅僅被需要使用一次。
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 productprint_r($factory->getSecondProduct()->getName());// Second productprint_r($factory->getFirstProduct()->getName());// The first product Prototype(原型模式)
有些時候,部分對象需要被初始化多次。而特別是在如果初始化需要耗費大量時間與資源的時候進行預初始化並且儲存下這些對象。
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 productprint_r($secondProduct->name);// Second product Builder(構造者)
構造者模式主要在於建立一些複雜的對象:
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 builderprint_r($secondDirector->getProduct()->getName());// The product of second builder Structural Patterns Decorator(裝飾器模式)
裝飾器模式允許我們根據運行時不同的情景動態地為某個對象調用前後添加不同的行為動作。
_html = "__text__
"; } 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("" . $this->_html . "
"); } 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("" . $this->_html . ""); } public function __call($name, $args) { $this->_element->$name($args[0]); }}
Adapter(適配器模式)
這種模式允許使用不同的介面重構某個類,可以允許使用不同的調用方式進行調用:
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."
";} Behavioral Patterns Strategy(策略模式)
測試模式主要為了讓客戶類能夠更好地使用某些演算法而不需要知道其具體的實現。
Observer(觀察者模式)
某個對象可以被設定為是可觀察的,只要通過某種方式允許其他對象註冊為觀察者。每當被觀察的對象改變時,會發送資訊給觀察者。
_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" ); Chain of responsibility(責任鏈模式)
這種模式有另一種稱呼:控制鏈模式。它主要由一系列對於某些命令的處理器構成,每個查詢會在處理器構成的責任鏈中傳遞,在每個交匯點由處理器判斷是否需要對它們進行響應與處理。每次的處理常式會在有處理器處理這些請求時暫停。
_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);