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应用的开发中,常常用于允许在运行时为某个特定的类创建一个可访问的实例。
<?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[] = ;
SecondProduct::getInstance()->a[] = ;
FirstProduct::getInstance()->a[] = ;
SecondProduct::getInstance()->a[] = ; print_r(FirstProduct::getInstance()->a);
// array(1, 3)
print_r(SecondProduct::getInstance()->a);
// array(2, 4)
Registry
注册台模式并不是很常见,它也不是一个典型的创建模式,只是为了利用静态方法更方便的存取数据。
<?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
Factory(工厂模式)
工厂模式是另一种非常常用的模式,正如其名字所示:确实是对象实例的生产工厂。某些意义上,工厂模式提供了通用的方法有助于我们去获取对象,而不需要关心其具体的内在的实现。
<?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
AbstractFactory(抽象工厂模式)
有些情况下我们需要根据不同的选择逻辑提供不同的构造工厂,而对于多个工厂而言需要一个统一的抽象工厂:
<?php class Config {
public static $factory = ;
} interface Product {
public function getName();
} abstract class AbstractFactory { public static function getFactory() {
switch (Config::$factory) {
case :
return new FirstFactory();
case :
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 = ;
$secondProduct = AbstractFactory::getFactory()->getProduct(); print_r($firstProduct->getName());
// The first product from the first factory
print_r($secondProduct->getName());
// Second product from second factory
Object pool(对象池)
对象池可以用于构造并且存放一系列的对象并在需要时获取调用:
<?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
Lazy Initialization(延迟初始化)
对于某个变量的延迟初始化也是常常被用到的,对于一个类而言往往并不知道它的哪个功能会被用到,而部分功能往往是仅仅被需要使用一次。
<?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
Prototype(原型模式)
有些时候,部分对象需要被初始化多次。而特别是在如果初始化需要耗费大量时间与资源的时候进行预初始化并且存储下这些对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
<?php interface Product { |
Builder(构造者)
构造者模式主要在于创建一些复杂的对象:
<?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
Structural Patterns
Decorator(装饰器模式)
装饰器模式允许我们根据运行时不同的情景动态地为某个对象调用前后添加不同的行为动作。
<?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[]);
}
} 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[]);
}
}
Adapter(适配器模式)
这种模式允许使用不同的接口重构某个类,可以允许使用不同的调用方式进行调用:
<?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/>";
}
Behavioral Patterns
Strategy(策略模式)
测试模式主要为了让客户类能够更好地使用某些算法而不需要知道其具体的实现。
<?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;
}
}
Observer(观察者模式)
某个对象可以被设置为是可观察的,只要通过某种方式允许其他对象注册为观察者。每当被观察的对象改变时,会发送信息给观察者。
<?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" );
Chain of responsibility(责任链模式)
这种模式有另一种称呼:控制链模式。它主要由一系列对于某些命令的处理器构成,每个查询会在处理器构成的责任链中传递,在每个交汇点由处理器判断是否需要对它们进行响应与处理。每次的处理程序会在有处理器处理这些请求时暂停。
<?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);
http://blog.jobbole.com/103565/
PHP 实战之设计模式:PHP 中的设计模式的更多相关文章
- [Head First设计模式]餐馆中的设计模式——命令模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- [设计模式]JDK中的设计模式
转载自:http://blog.csdn.net/gtuu0123/article/details/6114197 本文主要是归纳了JDK中所包含的设计模式,包括作用和其设计类图. 首先来个总结,具体 ...
- [Android]GOF23种设计模式 & Android中的设计模式
GOF23种设计模式 设计原则: 1. 单一职责原则(SRP):就一个类而言,应该仅有一个引起它变化的原因 2. 开放-封闭原则(OCP):软件实体(类.模块.函数等)应该可以扩展,但是不可修改.即对 ...
- 访何红辉:谈谈Android源码中的设计模式
最近Android 6.0版本的源代码开放下载,刚好分析Android源码的技术书籍<Android源码设计模式解析与实战>上市,我们邀请到它的作者何红辉,来谈谈Android源码中的设计 ...
- 初探Java设计模式4:一文带你掌握JDK中的设计模式
转自https://javadoop.com/post/design-pattern 行为型模式 策略模式 观察者模式 责任链模式 模板方法模式 状态模式 行为型模式总结 本系列文章将整理到我在Git ...
- [Head First设计模式]山西面馆中的设计模式——观察者模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 引言 不知不自觉又将设计模式融入生活了,吃个饭也不得安生,也发现生活中的很多场景,都可以用设计模式来模拟.原来设计模式就在 ...
- [Head First设计模式]山西面馆中的设计模式——建造者模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 引言 将学习融入生活中,是件很happy的事情,不会感 ...
- [Head First设计模式]饺子馆(冬至)中的设计模式——工厂模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- [Head First设计模式]抢票中的设计模式——代理模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- Spring中的设计模式
[Spring中的设计模式] http://www.uml.org.cn/j2ee/201301074.asp [详解设计模式在Spring中的应用] [http://www.geek521.c ...
随机推荐
- Vue(二):调试神器vue-devtools安装和使用
前言 vue-devtools是一款基于chrome游览器的插件,用于调试vue应用,这可以极大地提高我们的调试效率.接下来我们就介绍一下vue-devtools的安装. 安装 1.chrome商店直 ...
- 用bundler安装jeklly
为什么要写这篇文章呢?因为官方的安装文档里,ruby的很多库没有说明怎么安装.所以需要重点说明一下.1.我的安装环境是vultr的16.04版的ubuntu.2.因为ruby的扩展库好多都是Gcc编译 ...
- mui封装做好的手机版网站为apk
BOSS提到的一个功能,就是把已经做好的手机网站http://xxx.com/m/home/index ,想着看起来应该蛮简单,一个html页面里就一个iframe就好了,然后宽度和高度都设置为100 ...
- 【Unity】11.7 布料
分类:Unity.C#.VS2015 创建日期:2016-05-02 一.简介 Unity提供了两种布料组件:交互布料(Interactive Cloth).蒙皮布料(Skinned Cloth).为 ...
- vue2.0 组件化及组件传值
组件 (Component) 是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能.在有些情况下, ...
- scikit-learn:6. Strategies to scale computationally: bigger data
參考:http://scikit-learn.org/stable/modules/scaling_strategies.html 对于examples.features(或者两者)数量非常大的情况, ...
- IP地址格式转换(htonl、ntohl;inet_addr、inet_ntoa)
名词解析: 主机字节序: 不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序,这个叫做主机序.最常见的有两种 1.Little endian:低字节存高地址,高字节存低地址 2.Bi ...
- (转) Lua: 给 Redis 用户的入门指导
可能你已经听说过Redis 中嵌入了脚本语言,但是你还没有亲自去尝试吧? 这个入门教程会让你学会在你的Redis 服务器上使用强大的lua语言. Hello, Lua! 我们的第一个Redis Lu ...
- LeetCode: Binary Tree Inorder Traversal 解题报告
Binary Tree Inorder Traversal Given a binary tree, return the inorder traversal of its nodes' values ...
- 通用后台管理系统(ExtJS 4.2 + Spring MVC 3.2 + Hibernate)
通用后台管理系统(ExtJS 4.2 +Spring MVC 3.2 + Hibernate) 开发语言JAVA 成品成品 前端技术extjs 数据库mysql,sql server,oracle 系 ...