PhpDesignPatterns 【PHP 中的设计模式】
一、 Introduction【介绍】
设计模式:提供了一种广泛的可重用的方式来解决我们日常编程中常常遇见的问题。设计模式并不一定就是一个类库或者第三方框架,它们更多的表现为一种思想并且广泛地应用在系统中。它们也表现为一种模式或者模板,可以在多个不同的场景下用于解决问题。设计模式可以用于加速开发,并且将很多大的想法或者设计以一种简单地方式实现。当然,虽然设计模式在开发中很有作用,但是千万要避免在不适当的场景误用它们。
二、 Category【分类】
根据目的和范围,设计模式可以分为五类。
按照目的分为:创建设计模式,结构设计模式,以及行为设计模式。
按照范围分为:类的设计模式,以及对象设计模式。
1. 按照目的分,目前常见的设计模式主要有23种,根据使用目标的不同可以分为以下三大类:
-
创建设计模式(Creational Patterns)(5种):用于创建对象时的设计模式。更具体一点,初始化对象流程的设计模式。当程序日益复杂时,需要更加灵活地创建对象,同时减少创建时的依赖。而创建设计模式就是解决此问题的一类设计模式。
- 单例模式【Singleton】
- 工厂模式【Factory】
- 抽象工厂模式【AbstractFactory】
- 建造者模式【Builder】
- 原型模式【Prototype】
-
结构设计模式(Structural Patterns)(7种):用于继承和接口时的设计模式。结构设计模式用于新类的函数方法设计,减少不必要的类定义,减少代码的冗余。
- 适配器模式【Adapter】
- 桥接模式【Bridge】
- 合成模式【Composite】
- 装饰器模式【Decorator】
- 门面模式【Facade】
- 代理模式【Proxy】
- 享元模式【Flyweight】
-
行为模式(Behavioral Patterns)(11种):用于方法实现以及对应算法的设计模式,同时也是最复杂的设计模式。行为设计模式不仅仅用于定义类的函数行为,同时也用于不同类之间的协议、通信。
- 策略模式【Strategy】
- 模板方法模式【TemplateMethod】
- 观察者模式【Observer】
- 迭代器模式【Iterator】
- 责任链模式【ResponsibilityChain】
- 命令模式【Command】
- 备忘录模式【Memento】
- 状态模式【State】
- 访问者模式【Visitor】
- 中介者模式【Mediator】
- 解释器模式【Interpreter】
2.按照范围分为:类的设计模式,以及对象设计模式
三、 DesignPatternsPrinciple【设计模式原则】
设计模式六大原则
- 开放封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
- 里氏替换原则:所有引用基类的地方必须能透明地使用其子类的对象.
- 依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
- 单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
- 接口隔离原则:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
- 迪米特法则:一个对象应该对其他对象保持最少的了解。
四、 Realization【设计模式实现】
Creational Patterns(创建设计模式)
1. Singleton(单例模式)
- Singleton(单例模式):单例模式是最常见的模式之一,在Web应用的开发中,常常用于允许在运行时为某个特定的类创建仅有一个可访问的实例。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
private static $instance;
-
-
-
-
-
-
-
-
-
-
-
-
-
public static functiongetInstance()
-
-
if (! (self::$instance instanceof self)) {
-
self::$instance = new self();
-
-
-
-
-
-
-
-
private function__construct()
-
-
-
-
-
-
private function__clone()
-
-
trigger_error(‘Clone is not allowed !‘);
-
-
-
-
-
$firstMysql = Mysql::getInstance();
-
$secondMysql = Mysql::getInstance();
-
-
$firstMysql->mix = ‘ityangs_one‘;
-
$secondMysql->mix = ‘ityangs_two‘;
-
-
print_r($firstMysql->mix);
-
-
print_r($secondMysql->mix);
-
在很多情况下,需要为系统中的多个类创建单例的构造方式,这样,可以建立一个通用的抽象父工厂方法:
-
-
-
-
-
-
abstract classFactoryAbstract{
-
-
protected static $instances = array();
-
-
public static functiongetInstance(){
-
$className = self::getClassName();
-
if (!(self::$instances[$className] instanceof $className)) {
-
self::$instances[$className] = new $className();
-
-
return self::$instances[$className];
-
-
-
public static functionremoveInstance(){
-
$className = self::getClassName();
-
if (array_key_exists($className, self::$instances)) {
-
unset(self::$instances[$className]);
-
-
-
-
final protected static functiongetClassName(){
-
return get_called_class();
-
-
-
protected function__construct(){ }
-
-
final protected function__clone(){ }
-
-
-
abstract classFactoryextendsFactoryAbstract{
-
-
final public static functiongetInstance(){
-
return parent::getInstance();
-
-
-
final public static functionremoveInstance(){
-
parent::removeInstance();
-
-
-
-
-
classFirstProductextendsFactory{
-
-
-
classSecondProductextendsFirstProduct{
-
-
-
FirstProduct::getInstance()->a[] = 1;
-
SecondProduct::getInstance()->a[] = 2;
-
FirstProduct::getInstance()->a[] = 11;
-
SecondProduct::getInstance()->a[] = 22;
-
-
print_r(FirstProduct::getInstance()->a);
-
-
print_r(SecondProduct::getInstance()->a);
-
2. Factory(工厂模式)
工厂模式是另一种非常常用的模式,正如其名字所示:确实是对象实例的生产工厂。某些意义上,工厂模式提供了通用的方法有助于我们去获取对象,而不需要关心其具体的内在的实现。
-
-
-
-
-
-
-
-
-
public function createSystem($type);
-
-
-
classMySystemFactoryimplementsSystemFactory
-
-
-
public function createSystem($type)
-
-
-
-
-
-
-
-
return new LinuxSystem();
-
-
-
-
-
-
classWinSystemextendsSystem{ }
-
classMacSystemextendsSystem{ }
-
classLinuxSystemextendsSystem{ }
-
-
-
$System_obj = new MySystemFactory();
-
-
var_dump($System_obj->createSystem(‘Mac‘));
-
var_dump($System_obj->createSystem(‘Win‘));
-
var_dump($System_obj->createSystem(‘Linux‘));
3. AbstractFactory(抽象工厂模式)
有些情况下我们需要根据不同的选择逻辑提供不同的构造工厂,而对于多个工厂而言需要一个统一的抽象工厂:
-
-
-
-
-
-
classMacSystemextendsSystem{}
-
classMacSoftextendsSoft{}
-
-
classWinSystemextendsSystem{}
-
classWinSoftextendsSoft{}
-
-
-
-
-
-
-
interfaceAbstractFactory{
-
public functionCreateSystem();
-
public functionCreateSoft();
-
-
-
classMacFactoryimplementsAbstractFactory{
-
public functionCreateSystem(){ return new MacSystem(); }
-
public functionCreateSoft(){ return new MacSoft(); }
-
-
-
classWinFactoryimplementsAbstractFactory{
-
public functionCreateSystem(){ return new WinSystem(); }
-
public functionCreateSoft(){ return new WinSoft(); }
-
-
-
-
-
-
-
-
-
-
-
$MacFactory_obj = new MacFactory();
-
-
var_dump($MacFactory_obj->CreateSystem());
-
var_dump($MacFactory_obj->CreateSoft());
-
-
-
-
$WinFactory_obj = new WinFactory();
-
-
var_dump($WinFactory_obj->CreateSystem());
-
var_dump($WinFactory_obj->CreateSoft());
4. Builder(建造者模式)
建造者模式主要在于创建一些复杂的对象。将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示的设计模式;
结构图:

-
-
-
-
-
-
-
-
publicfunction__construct(){ $this->_parts = array(); }
-
publicfunctionadd($part){ return array_push($this->_parts, $part); }
-
-
-
-
-
-
-
-
-
-
-
-
publicabstractfunctionbuildPart1();
-
publicabstractfunctionbuildPart2();
-
publicabstractfunctiongetResult();
-
-
-
-
-
-
-
-
classConcreteBuilderextendsBuilder{
-
-
publicfunction__construct(){ $this->_product = new Product(); }
-
publicfunctionbuildPart1(){ $this->_product->add("Part1"); }
-
publicfunctionbuildPart2(){ $this->_product->add("Part2"); }
-
publicfunctiongetResult(){ return$this->_product; }
-
-
-
-
-
-
-
publicfunction__construct(Builder $builder){
-
-
-
-
-
-
-
-
-
-
$buidler = new ConcreteBuilder();
-
$director = new Director($buidler);
-
$product = $buidler->getResult();
-
-
-
-
-
-
-
-
-
-
-
5. Prototype(原型模式)
有时候,部分对象需要被初始化多次。而特别是在如果初始化需要耗费大量时间与资源的时候进行预初始化并且存储下这些对象,就会用到原型模式:
-
-
-
-
-
-
-
interfacePrototype{ publicfunctioncopy(); }
-
-
-
-
-
-
classConcretePrototypeimplementsPrototype{
-
-
publicfunction__construct($name){ $this->_name = $name; }
-
publicfunctioncopy(){ returnclone$this;}
-
-
-
-
-
-
$object1 = new ConcretePrototype(new Test());
-
-
$object2 = $object1->copy();
-
-
Structural Patterns(结构设计模式)
6. Adapter(适配器模式)
这种模式允许使用不同的接口重构某个类,可以允许使用不同的调用方式进行调用:
-
-
-
-
-
-
publicfunctionsampleMethod1();
-
publicfunctionsampleMethod2();
-
-
-
-
publicfunctionsampleMethod1(){
-
-
-
-
-
classAdapterimplementsTarget{
-
-
-
publicfunction__construct(Adaptee $adaptee){
-
$this->_adaptee = $adaptee;
-
-
-
publicfunctionsampleMethod1(){
-
$this->_adaptee->sampleMethod1();
-
-
-
publicfunctionsampleMethod2(){
-
-
-
-
$adapter = new Adapter(new Adaptee());
-
$adapter->sampleMethod1();
-
$adapter->sampleMethod2();
-
-
-
-
-
-
-
-
publicfunctionsampleMethod1();
-
publicfunctionsampleMethod2();
-
-
-
-
publicfunctionsampleMethod1(){echo‘++++++++‘;}
-
-
-
classAdapter2extendsAdaptee2implementsTarget2{
-
publicfunctionsampleMethod2(){echo‘————————‘;}
-
-
-
$adapter = new Adapter2();
-
$adapter->sampleMethod1();
-
$adapter->sampleMethod2();
-
7. Bridge(桥接模式)
将抽象部分与它的实现部分分离,使他们都可以独立的变抽象与它的实现分离,即抽象类和它的派生类用来实现自己的对象
桥接与适配器模式的关系(适配器模式上面已讲解):
桥接属于聚合关系,两者关联 但不继承
适配器属于组合关系,适配者需要继承源
聚合关系:A对象可以包含B对象 但B对象不是A对象的一部分
-
-
-
-
-
-
abstractclassImplementor{
-
abstractpublicfunctionoperationImp();
-
-
-
classConcreteImplementorAextendsImplementor{
-
publicfunctionoperationImp(){echo"A";}
-
-
-
classConcreteImplementorBextendsImplementor{
-
publicfunctionoperationImp(){echo"B";}
-
-
-
-
-
-
-
-
abstractclassAbstraction{
-
-
publicfunctionoperation(){
-
$this->imp->operationImp();
-
-
-
classRefinedAbstractionextendsAbstraction{
-
publicfunction__construct(Implementor $imp){
-
-
-
publicfunctionoperation(){ $this->imp->operationImp(); }
-
-
-
-
-
-
-
-
$abstraction = new RefinedAbstraction(new ConcreteImplementorA());
-
$abstraction->operation();
-
$abstraction = new RefinedAbstraction(new ConcreteImplementorB());
-
$abstraction->operation();
-
8. Composite(合成模式)
组合模式(Composite Pattern)有时候又叫做部分-整体模式,用于将对象组合成树形结构以表示“部分-整体”的层次关系。组合模式使得用户对单个对象和组合对象的使用具有一致性。
常见使用场景:如树形菜单、文件夹菜单、部门组织架构图等。
-
-
-
-
-
-
-
publicfunctiongetComposite();
-
publicfunctionoperation();
-
-
-
classCompositeimplementsComponent{
-
-
publicfunction__construct(){ $this->_composites = array(); }
-
publicfunctiongetComposite(){ return$this; }
-
publicfunctionoperation(){
-
foreach ($this->_composites as $composite) {
-
-
-
-
-
publicfunctionadd(Component $component){
-
$this->_composites[] = $component;
-
-
-
publicfunctionremove(Component $component){
-
foreach ($this->_composites as $key => $row) {
-
if ($component == $row) { unset($this->_composites[$key]); returnTRUE; }
-
-
-
-
-
publicfunctiongetChild(){
-
return$this->_composites;
-
-
-
-
-
classLeafimplementsComponent{
-
-
publicfunction__construct($name){ $this->_name = $name; }
-
publicfunctionoperation(){}
-
publicfunctiongetComposite(){returnnull;}
-
-
-
-
$leaf1 = new Leaf(‘first‘);
-
$leaf2 = new Leaf(‘second‘);
-
-
$composite = new Composite();
-
-
-
-
-
$composite->remove($leaf2);
-
-
-
-
-
-
-
-
-
-
-
-
-
publicfunctiongetComposite();
-
publicfunctionoperation();
-
publicfunctionadd(Component $component);
-
publicfunctionremove(Component $component);
-
publicfunctiongetChild();
-
-
-
classCompositeimplementsComponent{
-
-
publicfunction__construct(){ $this->_composites = array(); }
-
publicfunctiongetComposite(){ return$this; }
-
publicfunctionoperation(){
-
foreach ($this->_composites as $composite) {
-
-
-
-
publicfunctionadd(Component $component){
-
$this->_composites[] = $component;
-
-
publicfunctionremove(Component $component){
-
foreach ($this->_composites as $key => $row) {
-
if ($component == $row) { unset($this->_composites[$key]); returnTRUE; }
-
-
-
-
publicfunctiongetChild(){
-
return$this->_composites;
-
-
-
-
-
classLeafimplementsComponent{
-
-
publicfunction__construct($name){$this->_name = $name;}
-
publicfunctionoperation(){echo$this->_name."<br>";}
-
publicfunctiongetComposite(){ returnnull; }
-
publicfunctionadd(Component $component){ returnFALSE; }
-
publicfunctionremove(Component $component){ returnFALSE; }
-
publicfunctiongetChild(){ returnnull; }
-
-
-
-
$leaf1 = new Leaf(‘first‘);
-
$leaf2 = new Leaf(‘second‘);
-
-
$composite = new Composite();
-
-
-
-
-
$composite->remove($leaf2);
-
-
-
9. Decorator(装饰器模式)
装饰器模式允许我们根据运行时不同的情景动态地为某个对象调用前后添加不同的行
-
-
-
publicfunctionoperation();
-
-
-
abstractclassDecoratorimplementsComponent{
-
-
publicfunction__construct(Component $component){
-
$this->_component = $component;
-
-
publicfunctionoperation(){
-
$this->_component->operation();
-
-
-
-
classConcreteDecoratorAextendsDecorator{
-
publicfunction__construct(Component $component){
-
parent::__construct($component);
-
-
publicfunctionoperation(){
-
-
$this->addedOperationA();
-
-
publicfunctionaddedOperationA(){echo‘A加点酱油;‘;}
-
-
-
classConcreteDecoratorBextendsDecorator{
-
publicfunction__construct(Component $component){
-
parent::__construct($component);
-
-
publicfunctionoperation(){
-
-
$this->addedOperationB();
-
-
publicfunctionaddedOperationB(){echo"B加点辣椒;";}
-
-
-
classConcreteComponentimplementsComponent{
-
publicfunctionoperation(){}
-
-
-
-
$component = new ConcreteComponent();
-
$decoratorA = new ConcreteDecoratorA($component);
-
$decoratorB = new ConcreteDecoratorB($decoratorA);
-
-
$decoratorA->operation();
-
-
$decoratorB->operation();
-
10. Facade(门面模式)
门面模式 (Facade)又称外观模式,用于为子系统中的一组接口提供一个一致的界面。门面模式定义了一个高层接口,这个接口使得子系统更加容易使用:引入门面角色之后,用户只需要直接与门面角色交互,用户与子系统之间的复杂关系由门面角色来实现,从而降低了系统的耦
-
-
-
-
publicfunctionturnOff(){}
-
publicfunctionrotate($degrees){}
-
-
-
-
-
publicfunctionturnOff(){}
-
publicfunctionchangeBulb(){}
-
-
-
-
publicfunctionactivate(){}
-
publicfunctiondeactivate(){}
-
publicfunctiontrigger(){}
-
-
-
-
publicfunctionactivate(){}
-
publicfunctiondeactivate(){}
-
-
publicfunctionstopRing(){}
-
-
-
-
private $_camera1, $_camera2;
-
private $_light1, $_light2, $_light3;
-
-
-
-
publicfunction__construct(){
-
$this->_camera1 = new Camera();
-
$this->_camera2 = new Camera();
-
-
$this->_light1 = new Light();
-
$this->_light2 = new Light();
-
$this->_light3 = new Light();
-
-
$this->_sensor = new Sensor();
-
$this->_alarm = new Alarm();
-
-
-
publicfunctionactivate(){
-
$this->_camera1->turnOn();
-
$this->_camera2->turnOn();
-
-
$this->_light1->turnOn();
-
$this->_light2->turnOn();
-
$this->_light3->turnOn();
-
-
$this->_sensor->activate();
-
$this->_alarm->activate();
-
-
-
publicfunctiondeactivate(){
-
$this->_camera1->turnOff();
-
$this->_camera2->turnOff();
-
-
$this->_light1->turnOff();
-
$this->_light2->turnOff();
-
$this->_light3->turnOff();
-
-
$this->_sensor->deactivate();
-
$this->_alarm->deactivate();
-
-
-
-
-
-
$security = new SecurityFacade();
-
-
11. Proxy(代理模式)
代理模式(Proxy)为其他对象提供一种代理以控制对这个对象的访问。使用代理模式创建代理对象,让代理对象控制目标对象的访问(目标对象可以是远程的对象、创建开销大的对象或需要安全控制的对象),并且可以在不改变目标对象的情况下添加一些额外的功能。
在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。
经典例子就是网络代理,你想访问 Facebook 或者 Twitter ,如何绕过 GFW?找个代理
-
-
-
abstractpublicfunctionaction();
-
-
-
classRealSubjectextendsSubject{
-
publicfunction__construct(){}
-
-
-
-
classProxySubjectextendsSubject{
-
private $_real_subject = NULL;
-
publicfunction__construct(){}
-
-
-
-
if (is_null($this->_real_subject)) {
-
$this->_real_subject = new RealSubject();
-
-
$this->_real_subject->action();
-
-
-
-
privatefunction_beforeAction(){
-
echo‘在action前,我想干点啥....‘;
-
-
-
privatefunction_afterAction(){
-
echo‘在action后,我还想干点啥....‘;
-
-
-
-
-
$subject = new ProxySubject();
-
-
12. Flyweight(享元模式)
运用共享技术有效的支持大量细粒度的对象
享元模式变化的是对象的存储开销
享元模式中主要角色:
抽象享元(Flyweight)角色:此角色是所有的具体享元类的超类,为这些类规定出需要实现的公共接口。那些需要外运状态的操作可以通过调用商业以参数形式传入
具体享元(ConcreteFlyweight)角色:实现Flyweight接口,并为内部状态(如果有的话)拉回存储空间。ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的
不共享的具体享元(UnsharedConcreteFlyweight)角色:并非所有的Flyweight子类都需要被共享。Flyweigth使共享成为可能,但它并不强制共享
享元工厂(FlyweightFactory)角色:负责创建和管理享元角色。本角色必须保证享元对象可能被系统适当地共享
客户端(Client)角色:本角色需要维护一个对所有享元对象的引用。本角色需要自行存储所有享元对象的外部状态
享元模式的优点:
Flyweight模式可以大幅度地降低内存中对象的数量
享元模式的缺点:
Flyweight模式使得系统更加复杂
Flyweight模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长
享元模式适用场景:
当一下情况成立时使用Flyweight模式:
1 一个应用程序使用了大量的对象
2 完全由于使用大量的对象,造成很大的存储开销
3 对象的大多数状态都可变为外部状态
4 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象
5 应用程序不依赖于对象标识
-
-
-
-
-
abstract public functionoperate();
-
-
-
classunShareFlyWeightextendsResources{
-
public function__construct($resource_str){
-
$this->resource = $resource_str;
-
-
-
public functionoperate(){
-
echo $this->resource."<br>";
-
-
-
-
classshareFlyWeightextendsResources{
-
private $resources = array();
-
-
public functionget_resource($resource_str){
-
if(isset($this->resources[$resource_str])) {
-
return $this->resources[$resource_str];
-
-
return $this->resources[$resource_str] = $resource_str;
-
-
-
-
public functionoperate(){
-
foreach ($this->resources as $key => $resources) {
-
echo $key.":".$resources."<br>";
-
-
-
-
-
-
-
$flyweight = new shareFlyWeight();
-
$flyweight->get_resource(‘a‘);
-
-
-
-
$flyweight->get_resource(‘b‘);
-
-
-
$flyweight->get_resource(‘c‘);
-
-
-
-
$uflyweight = new unShareFlyWeight(‘A‘);
-
-
-
$uflyweight = new unShareFlyWeight(‘B‘);
-
-
-
-
-
-
-
-
-
-
Behavioral Patterns(行为模式)
13. Strategy(策略模式)
策略模式主要为了让客户类能够更好地使用某些算法而不需要知道其具体的实现。
-
-
-
publicfunctiondo_method();
-
-
-
classConcreteStrategyAimplementsStrategy{
-
publicfunctiondo_method(){
-
-
-
-
-
classConcreteStrategyBimplementsStrategy{
-
publicfunctiondo_method(){
-
-
-
-
-
classConcreteStrategyCimplementsStrategy{
-
publicfunctiondo_method(){
-
-
-
-
-
-
-
-
-
publicfunction__construct(Strategy $strategy){
-
$this->_strategy = $strategy;
-
-
publicfunctionhandle_question(){
-
$this->_strategy->do_method();
-
-
-
-
-
$strategyA = new ConcreteStrategyA();
-
$question = new Question($strategyA);
-
$question->handle_question();
-
-
$strategyB = new ConcreteStrategyB();
-
$question = new Question($strategyB);
-
$question->handle_question();
-
-
$strategyC = new ConcreteStrategyC();
-
$question = new Question($strategyC);
-
$question->handle_question();
-
14. TemplateMethod(模板方法模式)
模板模式准备一个抽象类,将部分逻辑以具体方法以及具体构造形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先制定一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。
-
-
abstractclassAbstractClass{
-
publicfunctiontemplateMethod(){
-
$this->primitiveOperation1();
-
$this->primitiveOperation2();
-
-
abstractprotectedfunctionprimitiveOperation1();
-
abstractprotectedfunctionprimitiveOperation2();
-
-
-
classConcreteClassextendsAbstractClass{
-
protectedfunctionprimitiveOperation1(){}
-
protectedfunctionprimitiveOperation2(){}
-
-
-
-
$class = new ConcreteClass();
-
$class->templateMethod();
-
15. Observer(观察者模式)
某个对象可以被设置为是可观察的,只要通过某种方式允许其他对象注册为观察者。每当被观察的对象改变时,会发送信息给观察者。
-
-
-
-
functiononSendMsg( $sender, $args );
-
-
-
-
-
functionaddObserver( $observer );
-
-
-
classUserListimplementsIObservable{
-
private $_observers = array();
-
-
publicfunctionsendMsg( $name ){
-
foreach( $this->_observers as $obs ){
-
$obs->onSendMsg( $this, $name );
-
-
-
-
publicfunctionaddObserver( $observer ){
-
$this->_observers[]= $observer;
-
-
-
publicfunctionremoveObserver($observer_name){
-
foreach($this->_observers as $index => $observer) {
-
if ($observer->getName() === $observer_name) {
-
array_splice($this->_observers, $index, 1);
-
-
-
-
-
-
-
classUserListLoggerimplementsIObserver{
-
publicfunctiononSendMsg( $sender, $args ){
-
echo( "‘$args‘ send to UserListLogger\n" );
-
-
-
-
-
-
-
-
classOtherObserverimplementsIObserver{
-
publicfunctiononSendMsg( $sender, $args ){
-
echo( "‘$args‘ send to OtherObserver\n" );
-
-
-
-
-
-
-
-
-
-
$ul->addObserver( new UserListLogger() );
-
$ul->addObserver( new OtherObserver() );
-
-
-
$ul->removeObserver(‘UserListLogger‘);
-
-
-
-
16. Iterator(迭代器模式)
迭代器模式 (Iterator),又叫做游标(Cursor)模式。提供一种方法访问一个容器(Container)对象中各个元素,而又不需暴露该对象的内部细节。
当你需要访问一个聚合对象,而且不管这些对象是什么都需要遍历的时候,就应该考虑使用迭代器模式。另外,当需要对聚集有多种方式遍历时,可以考虑去使用迭代器模式。迭代器模式为遍历不同的聚集结构提供如开始、下一个、是否结束、当前哪一项等统一的接口。
php标准库(SPL)中提供了迭代器接口 Iterator,要实现迭代器模式,实现该接口即可。
-
-
classsampleimplementsIterator{
-
-
-
publicfunction__construct(&$data){
-
-
-
-
return current($this->_items);
-
-
-
-
-
-
-
-
return key($this->_items);
-
-
-
-
-
-
-
-
return ($this->current() !== FALSE);
-
-
-
-
-
$data = array(1, 2, 3, 4, 5);
-
-
foreach ($sa AS $key => $row) {
-
echo $key, ‘ ‘, $row, ‘<br />‘;
-
-
-
-
-
-
-
-
-
-
classCMapIteratorimplementsIterator{
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
publicfunction__construct(&$data){
-
-
$this->_keys=array_keys($data);
-
-
-
-
-
-
-
-
$this->_key=reset($this->_keys);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
return$this->_d[$this->_key];
-
-
-
-
-
-
-
-
$this->_key=next($this->_keys);
-
-
-
-
-
-
-
-
-
return$this->_key!==false;
-
-
-
-
$data = array(‘s1‘ => 11, ‘s2‘ => 22, ‘s3‘ => 33);
-
$it = new CMapIterator($data);
-
-
-
-
-
-
-
-
-
17. ResponsibilityChain(责任链模式)
这种模式有另一种称呼:控制链模式。它主要由一系列对于某些命令的处理器构成,每个查询会在处理器构成的责任链中传递,在每个交汇点由处理器判断是否需要对它们进行响应与处理。每次的处理程序会在有处理器处理这些请求时暂停。
-
-
-
abstractclassResponsibility{
-
-
-
publicfunctionsetNext(Responsibility $l){
-
-
-
-
abstractpublicfunctionoperate();
-
-
-
classResponsibilityAextendsResponsibility{
-
publicfunction__construct(){}
-
-
if (false == is_null($this->next)) {
-
-
echo‘Res_A start‘."<br>";
-
-
-
-
-
classResponsibilityBextendsResponsibility{
-
publicfunction__construct(){}
-
-
if (false == is_null($this->next)) {
-
-
-
-
-
-
-
$res_a = new ResponsibilityA();
-
$res_b = new ResponsibilityB();
-
-
-
18. Command(命令模式)
命令模式:在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式。
角色分析:
抽象命令:定义命令的接口,声明执行的方法。
具体命令:命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
命令接收者:接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
控制者:要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
-
-
-
-
-
-
classConcreteCommandimplementsCommand{
-
-
publicfunction__construct(Receiver $receiver){
-
$this->_receiver = $receiver;
-
-
-
$this->_receiver->action();
-
-
-
-
-
-
publicfunction__construct($name){
-
-
-
-
echo‘receive some cmd:‘.$this->_name;
-
-
-
-
-
-
publicfunction__construct(Command $command){
-
$this->_command = $command;
-
-
-
$this->_command->execute();
-
-
-
-
$receiver = new Receiver(‘hello world‘);
-
$command = new ConcreteCommand($receiver);
-
$invoker = new Invoker($command);
-
-
备忘录模式又叫做快照模式(Snapshot)或 Token 模式,备忘录模式的用意是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样就可以在合适的时候将该对象恢复到原先保存的状态。
我们在编程的时候,经常需要保存对象的中间状态,当需要的时候,可以恢复到这个状态。比如,我们使用Eclipse进行编程时,假如编写失误(例如不小心误删除了几行代码),我们希望返回删除前的状态,便可以使用Ctrl+Z来进行返回。这时我们便可以使用备忘录模式来实现。
UML:

备忘录模式所涉及的角色有三个:备忘录(Memento)角色、发起人(Originator)角色、负责人(Caretaker)角色。
这三个角色的职责分别是:
发起人:记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和恢复备忘录数据。
备忘录:负责存储发起人对象的内部状态,在需要的时候提供发起人需要的内部状态。
管理角色:对备忘录进行管理,保存和提供备忘录。
-
-
-
-
-
publicfunction__construct(){
-
-
-
publicfunctioncreateMemento(){
-
returnnew Memento($this->_state);
-
-
publicfunctionrestoreMemento(Memento $memento){
-
$this->_state = $memento->getState();
-
-
publicfunctionsetState($state){ $this->_state = $state; }
-
publicfunctiongetState(){ return$this->_state; }
-
publicfunctionshowState(){
-
echo$this->_state;echo"<br>";
-
-
-
-
-
-
-
publicfunction__construct($state){
-
-
-
publicfunctiongetState(){ return$this->_state; }
-
publicfunctionsetState($state){ $this->_state = $state;}
-
-
-
-
-
publicfunctiongetMemento(){ return$this->_memento; }
-
publicfunctionsetMemento(Memento $memento){ $this->_memento = $memento; }
-
-
-
-
-
-
-
-
-
-
$memento = $org->createMemento();
-
-
-
$caretaker = new Caretaker();
-
$caretaker->setMemento($memento);
-
-
-
-
-
-
$org->restoreMemento($memento);
-
-
-
-
-
-
-
-
$org->restoreMemento($caretaker->getMemento());
-
-
-
-
-
-
-
-
20. State(状态模式)
状态模式当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
UML类图:

角色:
上下文环境(Work):它定义了客户程序需要的接口并维护一个具体状态角色的实例,将与状态相关的操作委托给当前的具体对象来处理。
抽象状态(State):定义一个接口以封装使用上下文环境的的一个特定状态相关的行为。
具体状态(AmState):实现抽象状态定义的接口。
-
-
-
publicfunctionhandle(Context $context);
-
-
-
classConcreteStateAimplementsState{
-
privatestatic $_instance = null;
-
privatefunction__construct(){}
-
publicstaticfunctiongetInstance(){
-
if (is_null(self::$_instance)) {
-
self::$_instance = new ConcreteStateA();
-
-
-
-
-
publicfunctionhandle(Context $context){
-
-
$context->setState(ConcreteStateB::getInstance());
-
-
-
-
-
classConcreteStateBimplementsState{
-
privatestatic $_instance = null;
-
privatefunction__construct(){}
-
publicstaticfunctiongetInstance(){
-
if (is_null(self::$_instance)) {
-
self::$_instance = new ConcreteStateB();
-
-
-
-
-
publicfunctionhandle(Context $context){
-
-
$context->setState(ConcreteStateA::getInstance());
-
-
-
-
-
-
publicfunction__construct(){
-
$this->_state = ConcreteStateA::getInstance();
-
-
publicfunctionsetState(State $state){
-
-
-
-
$this->_state->handle($this);
-
-
-
-
-
$context = new Context();
-
-
-
-
-
-
-
-
-
-
21. Visitor(访问者模式)
访问者模式是一种行为型模式,访问者表示一个作用于某对象结构中各元素的操作。它可以在不修改各元素类的前提下定义作用于这些元素的新操作,即动态的增加具体访问者角色。
访问者模式利用了双重分派。先将访问者传入元素对象的Accept方法中,然后元素对象再将自己传入访问者,之后访问者执行元素的相应方法。
主要角色
抽象访问者角色(Visitor):为该对象结构(ObjectStructure)中的每一个具体元素提供一个访问操作接口。该操作接口的名字和参数标识了 要访问的具体元素角色。这样访问者就可以通过该元素角色的特定接口直接访问它。
具体访问者角色(ConcreteVisitor):实现抽象访问者角色接口中针对各个具体元素角色声明的操作。
抽象节点(Node)角色:该接口定义一个accept操作接受具体的访问者。
具体节点(Node)角色:实现抽象节点角色中的accept操作。
对象结构角色(ObjectStructure):这是使用访问者模式必备的角色。它要具备以下特征:能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个复合(组合模式)或是一个集合,如一个列表或一个无序集合(在PHP中我们使用数组代替,因为PHP中的数组本来就是一个可以放置任何类型数据的集合)
适用性
访问者模式多用在聚集类型多样的情况下。在普通的形式下必须判断每个元素是属于什么类型然后进行相应的操作,从而诞生出冗长的条件转移语句。而访问者模式则可以比较好的解决这个问题。对每个元素统一调用element−>accept(vistor)即可。
访问者模式多用于被访问的类结构比较稳定的情况下,即不会随便添加子类。访问者模式允许被访问结构添加新的方法。
-
-
-
publicfunctionvisitConcreteElementA(ConcreteElementA $elementA);
-
publicfunctionvisitConcreteElementB(concreteElementB $elementB);
-
-
-
-
publicfunctionaccept(Visitor $visitor);
-
-
-
classConcreteVisitor1implementsVisitor{
-
publicfunctionvisitConcreteElementA(ConcreteElementA $elementA){}
-
publicfunctionvisitConcreteElementB(ConcreteElementB $elementB){}
-
-
-
classConcreteVisitor2implementsVisitor{
-
publicfunctionvisitConcreteElementA(ConcreteElementA $elementA){}
-
publicfunctionvisitConcreteElementB(ConcreteElementB $elementB){}
-
-
-
classConcreteElementAimplementsElement{
-
-
publicfunction__construct($name){ $this->_name = $name; }
-
publicfunctiongetName(){ return$this->_name; }
-
publicfunctionaccept(Visitor $visitor){
-
$visitor->visitConcreteElementA($this);
-
-
-
-
classConcreteElementBimplementsElement{
-
-
publicfunction__construct($name){ $this->_name = $name;}
-
publicfunctiongetName(){ return$this->_name; }
-
publicfunctionaccept(Visitor $visitor){
-
$visitor->visitConcreteElementB($this);
-
-
-
-
-
-
publicfunction__construct(){ $this->_collection = array(); }
-
publicfunctionattach(Element $element){
-
return array_push($this->_collection, $element);
-
-
publicfunctiondetach(Element $element){
-
$index = array_search($element, $this->_collection);
-
-
unset($this->_collection[$index]);
-
-
-
-
publicfunctionaccept(Visitor $visitor){
-
foreach ($this->_collection as $element) {
-
$element->accept($visitor);
-
-
-
-
-
-
$elementA = new ConcreteElementA("ElementA");
-
$elementB = new ConcreteElementB("ElementB");
-
$elementA2 = new ConcreteElementB("ElementA2");
-
$visitor1 = new ConcreteVisitor1();
-
$visitor2 = new ConcreteVisitor2();
-
-
$os = new ObjectStructure();
-
-
-
-
-
-
-
22. Mediator(中介者模式)
中介者模式用于开发一个对象,这个对象能够在类似对象相互之间不直接相互的情况下传送或者调解对这些对象的集合的修改。 一般处理具有类似属性,需要保持同步的非耦合对象时,最佳的做法就是中介者模式。PHP中不是特别常用的设计模式。
-
-
-
abstractpublicfunctionsend($message,$colleague);
-
-
-
-
private $_mediator = null;
-
publicfunction__construct($mediator){
-
$this->_mediator = $mediator;
-
-
publicfunctionsend($message){
-
$this->_mediator->send($message,$this);
-
-
abstractpublicfunctionnotify($message);
-
-
-
classConcreteMediatorextendsMediator{
-
private $_colleague1 = null;
-
private $_colleague2 = null;
-
publicfunctionsend($message,$colleague){
-
-
if($colleague == $this->_colleague1) {
-
$this->_colleague1->notify($message);
-
-
$this->_colleague2->notify($message);
-
-
-
publicfunctionset($colleague1,$colleague2){
-
$this->_colleague1 = $colleague1;
-
$this->_colleague2 = $colleague2;
-
-
-
-
classColleague1extendsColleague{
-
publicfunctionnotify($message){
-
echo‘colleague1:‘.$message."<br>";
-
-
-
-
classColleague2extendsColleague{
-
publicfunctionnotify($message){
-
echo‘colleague2:‘.$message."<br>";
-
-
-
-
-
$objMediator = new ConcreteMediator();
-
$objC1 = new Colleague1($objMediator);
-
$objC2 = new Colleague2($objMediator);
-
$objMediator->set($objC1,$objC2);
-
$objC1->send("to c2 from c1");
-
$objC2->send("to c1 from c2");
-
23. Interpreter(解释器模式)
给定一个语言, 定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
角色:
环境角色(PlayContent):定义解释规则的全局信息。
抽象解释器(Empress):定义了部分解释具体实现,封装了一些由具体解释器实现的接口。
具体解释器(MusicNote):实现抽象解释器的接口,进行具体的解释执行。
-
-
-
functioninterpreter($str){
-
-
-
-
-
classExpressionNumextendsExpression{
-
functioninterpreter($str){
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
classExpressionCharaterextendsExpression{
-
functioninterpreter($str){
-
-
-
-
-
-
functionexecute($string){
-
-
for($i = 0;$i<strlen($string);$i++) {
-
-
-
case is_numeric($temp): $expression = new ExpressionNum(); break;
-
default: $expression = new ExpressionCharater();
-
-
echo $expression->interpreter($temp);
-
-
-
-
-
-
-
$obj = new Interpreter();
-
$obj->execute("123s45abc");
-
-
-
-
-
-
-
-
-
-
-