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

來源:互聯網
上載者:User

本文為翻譯文章

原文地址: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 PatternsSingleton(單例模式)

單例模式是最常見的模式之一,在Web應用的開發中,常常用於允許在運行時為某個特定的類建立一個可訪問的執行個體。

  1. /**
  2. * Singleton class
  3. */
  4. final class Product
  5. {
  6. /**
  7. * @var self
  8. */
  9. private static $instance;
  10. /**
  11. * @var mixed
  12. */
  13. public $mix;
  14. /**
  15. * Return self instance
  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. }
  30. $firstProduct = Product::getInstance();
  31. $secondProduct = Product::getInstance();
  32. $firstProduct->mix = 'test';
  33. $secondProduct->mix = 'example';
  34. print_r($firstProduct->mix);
  35. // example
  36. print_r($secondProduct->mix);
  37. // example
複製代碼

在很多情況下,需要為系統中的多個類建立單例的構造方式,這樣,可以建立一個通用的抽象父Factory 方法:

  1. abstract class FactoryAbstract {
  2. protected static $instances = array();
  3. public static function getInstance() {
  4. $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 protected static function getClassName() {
  17. return get_called_class();
  18. }
  19. protected function __construct() { }
  20. final protected function __clone() { }
  21. }
  22. abstract class Factory extends FactoryAbstract {
  23. final public static function getInstance() {
  24. return parent::getInstance();
  25. }
  26. final public static function removeInstance() {
  27. parent::removeInstance();
  28. }
  29. }
  30. // using:
  31. class FirstProduct extends Factory {
  32. public $a = [];
  33. }
  34. class SecondProduct extends FirstProduct {
  35. }
  36. FirstProduct::getInstance()->a[] = 1;
  37. SecondProduct::getInstance()->a[] = 2;
  38. FirstProduct::getInstance()->a[] = 3;
  39. SecondProduct::getInstance()->a[] = 4;
  40. print_r(FirstProduct::getInstance()->a);
  41. // array(1, 3)
  42. print_r(SecondProduct::getInstance()->a);
  43. // array(2, 4)
複製代碼Registry

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

  1. /**
  2. * Registry class
  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. interface Product {
  5. public function getName();
  6. }
  7. class FirstFactory implements Factory {
  8. public function getProduct() {
  9. return new FirstProduct();
  10. }
  11. }
  12. class SecondFactory implements Factory {
  13. public function getProduct() {
  14. return new SecondProduct();
  15. }
  16. }
  17. class FirstProduct implements Product {
  18. public function getName() {
  19. return 'The first product';
  20. }
  21. }
  22. class SecondProduct implements Product {
  23. public function getName() {
  24. return 'Second product';
  25. }
  26. }
  27. $factory = new FirstFactory();
  28. $firstProduct = $factory->getProduct();
  29. $factory = new SecondFactory();
  30. $secondProduct = $factory->getProduct();
  31. print_r($firstProduct->getName());
  32. // The first product
  33. print_r($secondProduct->getName());
  34. // Second product
複製代碼AbstractFactory(抽象原廠模式)

有些情況下我們需要根據不同的選擇邏輯提供不同的構造工廠,而對於多個工廠而言需要一個統一的抽象工廠:

  1. class Config {
  2. public static $factory = 1;
  3. }
  4. interface Product {
  5. public function getName();
  6. }
  7. abstract class AbstractFactory {
  8. public static function getFactory() {
  9. switch (Config::$factory) {
  10. case 1:
  11. return new FirstFactory();
  12. case 2:
  13. return new SecondFactory();
  14. }
  15. throw new Exception('Bad config');
  16. }
  17. abstract public function getProduct();
  18. }
  19. class FirstFactory extends AbstractFactory {
  20. public function getProduct() {
  21. return new FirstProduct();
  22. }
  23. }
  24. class FirstProduct implements Product {
  25. public function getName() {
  26. return 'The product from the first factory';
  27. }
  28. }
  29. class SecondFactory extends AbstractFactory {
  30. public function getProduct() {
  31. return new SecondProduct();
  32. }
  33. }
  34. class SecondProduct implements Product {
  35. public function getName() {
  36. return 'The product from second factory';
  37. }
  38. }
  39. $firstProduct = AbstractFactory::getFactory()->getProduct();
  40. Config::$factory = 2;
  41. $secondProduct = AbstractFactory::getFactory()->getProduct();
  42. print_r($firstProduct->getName());
  43. // The first product from the first factory
  44. print_r($secondProduct->getName());
  45. // Second product from second factory
複製代碼Object pool(對象池)

對象池可以用於構造並且存放一系列的對象並在需要時擷取調用:

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

對於某個變數的延遲初始化也是常常被用到的,對於一個類而言往往並不知道它的哪個功能會被用到,而部分功能往往是僅僅被需要使用一次。

  1. interface Product {
  2. public function getName();
  3. }
  4. class Factory {
  5. protected $firstProduct;
  6. protected $secondProduct;
  7. public function getFirstProduct() {
  8. if (!$this->firstProduct) {
  9. $this->firstProduct = new FirstProduct();
  10. }
  11. return $this->firstProduct;
  12. }
  13. public function getSecondProduct() {
  14. if (!$this->secondProduct) {
  15. $this->secondProduct = new SecondProduct();
  16. }
  17. return $this->secondProduct;
  18. }
  19. }
  20. class FirstProduct implements Product {
  21. public function getName() {
  22. return 'The first product';
  23. }
  24. }
  25. class SecondProduct implements Product {
  26. public function getName() {
  27. return 'Second product';
  28. }
  29. }
  30. $factory = new Factory();
  31. print_r($factory->getFirstProduct()->getName());
  32. // The first product
  33. print_r($factory->getSecondProduct()->getName());
  34. // Second product
  35. print_r($factory->getFirstProduct()->getName());
  36. // The first product
複製代碼Prototype(原型模式)

有些時候,部分對象需要被初始化多次。而特別是在如果初始化需要耗費大量時間與資源的時候進行預初始化並且儲存下這些對象。

  1. interface Product {
  2. }
  3. class Factory {
  4. private $product;
  5. public function __construct(Product $product) {
  6. $this->product = $product;
  7. }
  8. public function getProduct() {
  9. return clone $this->product;
  10. }
  11. }
  12. class SomeProduct implements Product {
  13. public $name;
  14. }
  15. $prototypeFactory = new Factory(new SomeProduct());
  16. $firstProduct = $prototypeFactory->getProduct();
  17. $firstProduct->name = 'The first product';
  18. $secondProduct = $prototypeFactory->getProduct();
  19. $secondProduct->name = 'Second product';
  20. print_r($firstProduct->name);
  21. // The first product
  22. print_r($secondProduct->name);
  23. // 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->name;
  8. }
  9. }
  10. abstract class Builder {
  11. protected $product;
  12. final public function getProduct() {
  13. return $this->product;
  14. }
  15. public function buildProduct() {
  16. $this->product = new Product();
  17. }
  18. }
  19. class FirstBuilder extends Builder {
  20. public function buildProduct() {
  21. parent::buildProduct();
  22. $this->product->setName('The product of the first builder');
  23. }
  24. }
  25. class SecondBuilder extends Builder {
  26. public function buildProduct() {
  27. parent::buildProduct();
  28. $this->product->setName('The product of second builder');
  29. }
  30. }
  31. class Factory {
  32. private $builder;
  33. public function __construct(Builder $builder) {
  34. $this->builder = $builder;
  35. $this->builder->buildProduct();
  36. }
  37. public function getProduct() {
  38. return $this->builder->getProduct();
  39. }
  40. }
  41. $firstDirector = new Factory(new FirstBuilder());
  42. $secondDirector = new Factory(new SecondBuilder());
  43. print_r($firstDirector->getProduct()->getName());
  44. // The product of the first builder
  45. print_r($secondDirector->getProduct()->getName());
  46. // The product of second builder
複製代碼Structural PatternsDecorator(裝飾器模式)

裝飾器模式允許我們根據運行時不同的情景動態地為某個對象調用前後添加不同的行為動作。

  1. class HtmlTemplate {
  2. // any parent class methods
  3. }
  4. class Template1 extends HtmlTemplate {
  5. protected $_html;
  6. public function __construct() {
  7. $this->_html = "

    __text__

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

    " . $this->_html . "

    ");
  21. }
  22. public function __call($name, $args) {
  23. $this->_element->$name($args[0]);
  24. }
  25. }
  26. class Template3 extends HtmlTemplate {
  27. protected $_element;
  28. public function __construct($s) {
  29. $this->_element = $s;
  30. $this->set("" . $this->_html . "");
  31. }
  32. public function __call($name, $args) {
  33. $this->_element->$name($args[0]);
  34. }
  35. }
複製代碼Adapter(適配器模式)

這種模式允許使用不同的介面重構某個類,可以允許使用不同的調用方式進行調用:

  1. class SimpleBook {
  2. private $author;
  3. private $title;
  4. function __construct($author_in, $title_in) {
  5. $this->author = $author_in;
  6. $this->title = $title_in;
  7. }
  8. function getAuthor() {
  9. return $this->author;
  10. }
  11. function getTitle() {
  12. return $this->title;
  13. }
  14. }
  15. class BookAdapter {
  16. private $book;
  17. function __construct(SimpleBook $book_in) {
  18. $this->book = $book_in;
  19. }
  20. function getAuthorAndTitle() {
  21. return $this->book->getTitle().' by '.$this->book->getAuthor();
  22. }
  23. }
  24. // Usage
  25. $book = new SimpleBook("Gamma, Helm, Johnson, and Vlissides", "Design Patterns");
  26. $bookAdapter = new BookAdapter($book);
  27. echo 'Author and Title: '.$bookAdapter->getAuthorAndTitle();
  28. function echo $line_in) {
  29. echo $line_in."
    ";
  30. }
複製代碼Behavioral PatternsStrategy(策略模式)

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

  1. interface OutputInterface {
  2. public function load();
  3. }
  4. class SerializedArrayOutput implements OutputInterface {
  5. public function load() {
  6. return serialize($arrayOfData);
  7. }
  8. }
  9. class JsonStringOutput implements OutputInterface {
  10. public function load() {
  11. return json_encode($arrayOfData);
  12. }
  13. }
  14. class ArrayOutput implements OutputInterface {
  15. public function load() {
  16. return $arrayOfData;
  17. }
  18. }
複製代碼Observer(觀察者模式)

某個對象可以被設定為是可觀察的,只要通過某種方式允許其他對象註冊為觀察者。每當被觀察的對象改變時,會發送資訊給觀察者。

  1. interface Observer {
  2. function onChanged($sender, $args);
  3. }
  4. interface Observable {
  5. function addObserver($observer);
  6. }
  7. class CustomerList implements Observable {
  8. private $_observers = array();
  9. public function addCustomer($name) {
  10. foreach($this->_observers as $obs)
  11. $obs->onChanged($this, $name);
  12. }
  13. public function addObserver($observer) {
  14. $this->_observers []= $observer;
  15. }
  16. }
  17. class CustomerListLogger implements Observer {
  18. public function onChanged($sender, $args) {
  19. echo( "'$args' Customer has been added to the list \n" );
  20. }
  21. }
  22. $ul = new UserList();
  23. $ul->addObserver( new CustomerListLogger() );
  24. $ul->addCustomer( "Jack" );
複製代碼Chain of responsibility(責任鏈模式)

這種模式有另一種稱呼:控制鏈模式。它主要由一系列對於某些命令的處理器構成,每個查詢會在處理器構成的責任鏈中傳遞,在每個交匯點由處理器判斷是否需要對它們進行響應與處理。每次的處理常式會在有處理器處理這些請求時暫停。

  1. interface Command {
  2. function onCommand($name, $args);
  3. }
  4. class CommandChain {
  5. private $_commands = array();
  6. public function addCommand($cmd) {
  7. $this->_commands[]= $cmd;
  8. }
  9. public function runCommand($name, $args) {
  10. foreach($this->_commands as $cmd) {
  11. if ($cmd->onCommand($name, $args))
  12. return;
  13. }
  14. }
  15. }
  16. class CustCommand implements Command {
  17. public function onCommand($name, $args) {
  18. if ($name != 'addCustomer')
  19. return false;
  20. echo("This is CustomerCommand handling 'addCustomer'\n");
  21. return true;
  22. }
  23. }
  24. class MailCommand implements Command {
  25. public function onCommand($name, $args) {
  26. if ($name != 'mail')
  27. return false;
  28. echo("This is MailCommand handling 'mail'\n");
  29. return true;
  30. }
  31. }
  32. $cc = new CommandChain();
  33. $cc->addCommand( new CustCommand());
  34. $cc->addCommand( new MailCommand());
  35. $cc->runCommand('addCustomer', null);
  36. $cc->runCommand('mail', null);
複製代碼
PHP
  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.