首頁  >  文章  >  後端開發  >  PHP 實戰之設計模式:PHP 中的設計模式

PHP 實戰之設計模式:PHP 中的設計模式

WBOY
WBOY原創
2016-07-23 08:54:42797瀏覽
PHP

本文為翻譯文章

原文網址:Design Patterns in PHP
如果打算學習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應用的開發中,常用於允許在執行時間為某個特定的類別建立一個可存取的實例。

  1. /**
  2. * 單例類別
  3. */
  4. final class Product
  5. {
  6. /**
  7. * @var self
  8. */
  9. private static $instance;
  10. /**
  11. * @var 混合
  12. */
  13. public $mix;
  14. /**
  15. * 回傳自身實例
  16. *
  17. * @return self
  18. */
  19. public static function getInstance() {
  20. if (!(self::$instance instanceof self)) {
  21. self::$instance = new self();
  22. }
  23. return self: :$instance;
  24. }
  25. private function __construct() {
  26. }
  27. private function __clone() {
  28. }
  29. private function __clone() {
  30. }
  31. > $firstProduct = Product::getInstance();
  32. $secondProduct = Product::getInstance();
  33. $firstProduct->mix = 'test';
  34. $secondProduct->mix = '0 ';
  35. print_r($firstProduct->mix);
  36. // example
  37. print_r($secondProduct->mix);
  38. // example
複製程式碼

在許多情況下,需要為系統中的多個類別建立單例的構造方式,這樣,可以建立一個通用的抽象父工廠方法:
  1. abstract class FactoryAbstract {
  2. protected static $instances = array();
  3. public instances = array();
  4. public static function(Ingetst); 🎜> $className = static::getClassName();
  5. if (!(self::$instances[$className] instanceof $className)) {
  6. self::$instances[$className] = new $className ();
  7. }
  8. return self::$instances[$className];
  9. }
  10. public static function removeInstance() {
  11. $className = static::getClassName() ;
  12. if (array_key_exists($className, self::$instances)) {
  13. unset(self::$instances[$className]);
  14. }
  15. }
  16. final🎜> final🎜> final🎜> final🎜> final🎜> final🎜> final🎜> final🎜> final🎜> final🎜> final🎜> final🎜> final🎜> final🎜> final🎜> final🎜> final🎜> final🎜> final protected static function getClassName() {
  17. return get_called_class();
  18. }
  19. protected function __construct() { }
  20. final protected function protect(
  21. abstract class Factory extends FactoryAbstract {
  22. final public static function getInstance() {
  23. return parent::getInstance();
  24. }
  25. return parent::getInstance();
  26. }
  27. function removeInstance() {
  28. parent::removeInstance();
  29. }
  30. }
  31. // using:
  32. class FirstProduct extends Factory {
  33. class FirstProduct extends Factory {
  34. public $🎜> ;
  35. }
  36. class SecondProduct extends FirstProduct {
  37. }
  38. FirstProduct::getInstance()->a[] = 1;
  39. SecondProduct::getgetstance()->( ] = 2;
  40. FirstProduct::getInstance()->a[] = 3;
  41. SecondProduct::getInstance()->a[] = 4;
  42. print_r(FirstProduct::getInstance ()->a);
// array(1, 3)
print_r(SecondProduct::getInstance()->a);// array(2, 4)
複製程式碼Registry

註冊台模式並不是很常見,它也不是一個典型的創建模式,只是為了利用靜態方法更方便的存取資料。

  1. /**
  2. * 註冊表類
  3. */
  4. class Package {
  5. protected static $data = array();
  6. public static function set($key, $value) {
  7. self::$data[$key] = $value;
  8. }
  9. public static function get($ key) {
  10. return isset(self::$data[$key]) ? self::$data[$key] : null;
  11. }
  12. final public static function removeObject($key ) {
  13. if (array_key_exists($key, self::$data)) {
  14. unset(self::$data[$key]);
  15. }
  16. }
  17. }
  18. Package::set('name', 'Package name');
  19. print_r(Package::get('name'));
  20. // Package name
複製程式碼
Factory(工廠模式)

工廠模式是另一種非常常用的模式,正如其名字所示:確實是物件實例的生產工廠。在某些意義上,工廠模式提供了通用的方法有助於我們去獲取對象,而不需要關心其具體的內在的實現。

  1. interface Factory {
  2. public function getProduct();
  3. }
  4. public function getProduct();
  5. }
  6. face public function getName();
  7. }
  8. class FirstFactory implements Factory {
  9. public function getProduct() {
  10. return newProduct();
  11. >}
  12. class SecondFactory implements Factory {
  13. public function getProduct() {
  14. return new SecondProduct();
  15. }
  16. return new SecondProduct();
  17. }
  18. > implements Product {
  19. public function getName() {
  20. return 'The first product';
  21. }
  22. }
  23. class SecondProduct imple🎜>}
  24. class SecondProduct implelments Product> public function getName() {
  25. return 'Second product';
  26. }
  27. }
  28. $factory = new FirstFactory();
  29. $firstProduct = $factory = new FirstFactory();
  30. $firstProduct = $factory-getProduct(actory) ;
  31. $factory = new SecondFactory();
  32. $secondProduct = $factory->getProduct();
  33. print_r($firstProduct->getName());
  34. print_r($firstProduct->getName());
  35. // The first product
  36. print_r($secondProduct->getName());
// Second product
複製程式碼

AbstractFactory(抽象工廠模式)

有些情況下我們需要根據不同的選擇邏輯提供不同的構造工廠,而對於多個工廠而言需要一個統一的抽象工廠:
  1. php
  2. class Config {
  3. public static $factory = 1;
  4. }
  5. interface Product {
  6. public function getName();
  7. interface Product {
  8. public function getName();
  9. abstract class AbstractFactory {
  10. public static function getFactory() {
  11. switch (Config::$factory) {
  12. case 1:
  13. return new? 2:
  14. return new SecondFactory();
  15. }
  16. throw new Exception('Bad config');
  17. }
  18. abstract public function getProduct(); 🎜>
  19. class FirstFactory extends AbstractFactory {
  20. public function getProduct() {
  21. return new FirstProduct();
  22. }
  23. }
  24. class FirstProdupmplements Product class Pro () {
  25. return 'The product from the first factory';
  26. }
  27. }
  28. class SecondFactory extends AbstractFactory {
  29. public function getProduct() return }
  30. }
  31. class SecondProduct implements Product {
  32. public function getName() {
  33. return 'The product from second factory';
  34. }
  35. }
  36. >
  37. $firstProduct = AbstractFactory::getFactory()->getProduct();
  38. Config::$factory = 2;
  39. $secondProduct = AbstractFactory::getFactory()->getProduct();getProduct(); >
  40. print_r($firstProduct->getName());
  41. // The first product from the first factory
  42. print_r($secondProduct->getName());
  43. // Second product from second factory
  44. 複製程式碼
Object pool(物件池)

物件池可以用於建構並且存放一系列的物件並在需要時取得呼叫:

  1. class Product {
  2. protected $id;
  3. public function __construct($id) {
  4. $this->id = $id;
  5. }
  6. public ftion getId() {
  7. return $this->id;
  8. }
  9. }
  10. class Factory {
  11. protected static $products = array();
  12. publicy();
  13. 我static function pushProduct(Product $product) {
  14. self::$products[$product->getId()] = $product;
  15. }
  16. public static function getProduct($id) { 🎜> return isset(self::$products[$id]) ? self::$products[$id] : null;
  17. }
  18. public static function removeProduct($id) {
  19. public static function removeProduct($id) {
  20. if (array_key_exists($id, self::$products)) {
  21. unset(self::$products[$id]);
  22. }
  23. }
  24. }
  25. Factory::pushProduct(new Product('first'));
  26. Factory::pushProduct(new Product('second'));
  27. print_r(Factory::getProduct('first') ->getId());
  28. // first
  29. print_r(Factory::getProduct('second')->getId());
// second
複製程式碼

Lazy Initialization(延遲初始化)

對於某個變數的延遲初始化也是常常被用到的,對於一個類別而言往往並不知道它的哪個功能會被用到,而部分功能往往是僅僅被需要使用一次。
  1. interface Product {
  2. public function getName();
  3. }
  4. 🎜>
  5. protected $firstProduct;
  6. protected $secondProduct;
  7. public function getFirstProduct() {
  8. if (!$this->firstProduct() {
  9. if (!$this->firstProduct) new FirstProduct();
  10. }
  11. return $this->firstProduct;
  12. }
  13. public function getSecondProduct() {
  14. if (!$this->secondProduct) > $this->secondProduct = new SecondProduct();
  15. }
  16. return $this->secondProduct;
  17. }
  18. }
  19. class FirstProduct implements Product { return 'The first product';
  20. }
  21. }
  22. class SecondProduct implements Product {
  23. public function getName() {
  24. return 'Second ;
  25. }
  26. }
  27. $factory = new Factory();
  28. print_r($factory->getFirstProduct()->getName()); >// The first product
  29. print_r($factory->getSecondProduct()->getName());
  30. // Second product
  31. print_r($factory->getFirstProduct()->getName()) ;
  32. // The first product
  33. 複製程式碼
Prototype(原型模式) 有些時候,部分物件需要被初始化多次。而特別是在如果初始化需要耗費大量時間與資源的時候進行預初始化並且儲存下這些物件。

    interface Product {
  1. }
  2. class Factory {
  3. $ate $
  4. public function __construct(Product $product) {
  5. $this->product = $product;
  6. }
  7. public function getProduct() {
  8. ->product;
  9. }
  10. }
  11. class SomeProduct implements Product {
  12. public $name;
  13. }
  14. $prototypeFactory = new new new 樣0 SomeProduct());
  15. $firstProduct = $prototypeFactory->getProduct();
  16. $firstProduct->name = 'The first product';
  17. $secFactorct getProduct();
  18. $secondProduct->name = 'Second product';
  19. print_r($firstProduct->name);
  20. // The first product
  21. print_rct($ name);
  22. // Second product
複製程式碼
Builder(建造者)

建構者模式主要提供創建一些複雜的物件:

  1. class Product {
  2. private $ name ;
  3. public function setName($name) {
  4. $this->name = $name;
  5. }
  6. public function getName() {
  7. return $this this- >name;
  8. }
  9. }
  10. 抽象類別Builder {
  11. protected $product;
  12. 最終公用函數->product;
  13. }
  14. public function buildProduct() {
  15. $this->product = new Product();
  16. }
  17. }
  18. }
  19. }
  20. extends Builder {
  21. public function buildProduct() {
  22. parent::buildProduct();
  23. $this->product->setName('第一個的乘積
  24. }
  25. }
  26. class SecondBuilder extends Builder {
  27. public function buildProduct() {
  28. parent::buildProduct();
  29. $) {
  30. parent::buildProduct(); $) {
  31. parent:: '第二個建構器的產品');
  32. }
  33. }
  34. class Factory {
  35. private $builder;
  36. public function __construct(Builder $ builder) {
  37. $this->builder = $builder;
  38. $this->builder->buildProduct();
  39. }
  40. public function getProduct() {
  41. return $🎜> public function getProduct() {
  42. return $🎜> public function getProduct() {
  43. return $🎜> public function getProduct() {
  44. return $🎜> public function getProduct() {
return $ this->builder->getProduct();
}}
$firstDirector = new Factory(new FirstBuilder());

$secondDirector = new Factory(new FirstBuilder());

$secondDirector = new Factory(new FirstBuilderondBuilder(new) ;
print_r($firstDirector->getProduct()->getName());
    // 第一個建構器的產品
  1. print_r($secondDirector->getProduct()->getName ());
  2. // 第二個建構器的乘積
  3. 複製程式碼
  4. 結構模式 Decorator(裝飾器模式)
  5. 裝飾器模式允許我們根據不同的場景動態地運行某個物件呼叫前後添加不同的行為動作。
  6. class HtmlTemplate {
  7. // 任何父類方法
  8. }
  9. class Template1 extends Hthilate > protected $_html;
  10. public function __construct() {
  11. $ this->_html = "

    __text__

    ";
  12. }
  13. public function set ($html) {
  14. $this->_html = $html;
  15. }
  16. public function render() {
  17. echo $this->_html;
  18. }
  19. }
  20. }
  21. class Template2 extends HtmlTemplate {
  22. protected $ _element;
  23. public function __construct($s) {
  24. $this->_element = $s; ->set("

    " . $this-> ;_html . "

    ");
  25. }
  26. 公用函數__call($name, $args) {
  27. $this->_element->$name($args) [0]);
  28. }
  29. }
  30. 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] );
  1. }
  2. }
  3. 複製程式碼
  4. Adapter(適配器模式)
  5. 這種模式允許使用不同的介面重建某個類,可以允許使用不同的呼叫方式進行呼叫:
  6. class SimpleBook {
  7. private $author;
  8. private $title;
  9. function __construct($author_in, $title_in) {
  10. $this->author = $this->author = $authorin ;
  11. $this->author = $authorin ;
  12. $this->title = $title_in;
  13. }
  14. function getAuthor() {
  15. return $this->author;
  16. }
  17. function getTitle() {
  18. return $this->title;
  19. }
  20. }
  21. class BookAdapter {
  22. private $book;
  23. 函數
  24. private $book;
函數__🎜(SimpleBook__ book_in) {
$this->book = $book_in; } function getAuthorAndTitle() {
return $this->book->getTitle().' by '.$this-> book->getAuthor(); }}//用法$book = new SimpleBook("Gamma、Helm、Johnson 與Vlissides", "設計模式");$bookAdapter = new BookAdapter($book);echo '作者與標題:'.$bookAdapter->getAuthorAndTitle();function echo $line_in) { echoin_in. "
";}複製程式碼Behavioral Patterns Strategy(策略模式)

測試模式主要為了讓客戶類別能夠更好地使用某些演算法而不需要知道其具體的實作。

  1. interface OutputInterface {
  2. public function load();
  3. }
  4. public function load() {
  5. return serialize($arrayOfData);
  6. }
  7. }
  8. class JsonStringOutput implements OutputInterface {
  9. class JsonStringOutput implementsments > return json_encode($arrayOfData);
  10. }
  11. }
  12. class ArrayOutput implements OutputInterface {
  13. public function load() {
  14. return $arrayOfData; }
  15. 複製程式碼
Observer(觀察者模式) 某個物件可以被設定為是可觀察的,只要透過某種方式允許其他物件註冊為觀察者。每當被觀察的對象改變時,會傳送訊息給觀察者。

    interface Observer {
  1. function onChanged($sender, $args);
  2. }
  3. }
  4. interface Observable {
  5. function addObserver($observer);
  6. }
  7. class CustomerList implements Observable {
  8. private $_observers = array();
  9. foreach($this->_observers as $obs)
  10. $obs->onChanged($this, $name);
  11. }
  12. public function addObserver($observer) {
  13. $this->_observers []= $observer;
  14. }
  15. }
  16. class CustomerListLogger implements Observer {
  17. public function onChanged($sender, $argments > echo( "'$args' Customer has been added to the list n" );
  18. }
  19. }
  20. $ul = new UserList();
  21. $ul->addObserver( new CustomerListLogger() );
  22. $ul->addCustomer( "Jack" );
  23. 複製程式碼
Chain of responsibility(責任鏈模式)
這種模式有另一種稱呼:控制鏈模式。它主要由一系列對於某些命令的處理器構成,每個查詢都會在處理器構成的責任鏈中傳遞,在每個交匯點由處理器判斷是否需要對它們進行回應與處理。每次的處理程序會在有處理器處理這些請求時暫停。

interface Command {
    function onCommand($name, $args);
  1. }
  2. class CommandChain {
  3. private $_commands = array();
  4. public function addCommand($cmd) {
  5. $this->_commands[]= $cmd;
  6. }
  7. }
  8. public function runCommand($name, $args) {
  9. foreach($this->_commands as $cmd) {
  10. if ($cmd->onCommand($name, $args))
  11. return ;
  12. }
  13. }
  14. }
  15. class CustCommand implements Command {
  16. public function onCommand($name, $args) {
  17. if ($name != 'addCustomer' )
  18. return false;
  19. echo("This is CustomerCommand handling 'addCustomer'n");
  20. return true;
  21. }
  22. }
  23. class Command
  24. public function onCommand($name, $args) {
  25. if ($name != 'mail')
  26. return false;
  27. echo("This is MailCommand handling 'mail'n");
  28. return true;
  29. }
  30. }
  31. $cc = new CommandChain();
  32. $cc->addCommand( new CustCommand());
  33. $cc->addCommand ( new MailCommand());
  34. $cc->runCommand('addCustomer', null);
  35. $cc->runCommand('mail', null);
複製程式碼
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn