zoukankan      html  css  js  c++  java
  • Symfony2中的设计模式——装饰者模式

    装饰者模式的定义

       文章链接:http://www.hcoding.com/?p=101

      个人站点:http://www.hcoding.com/

      在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

      装饰者模式把每个要装饰的功能放在单独的类中,并让这个类包装它要装饰的对象,因此,当需要执行特殊行为时,客户端代码就可以在运行的时候根据需要有选择地、按顺序地使用装饰功能包装对象了。

    装饰者模式

    图1

    使用场景

      设想一下,如果我们需要创建一个在不同场合有不同着装的学生,例如:在学校学生需要穿上校服,在舞会学生需要穿上正装,在家学生可以裸装(有点变态),当然,还可以学习超人把底裤穿在外面。这时候问题来了,难道我们要为每种场合编写一个不同穿着的学生类吗?如果我们的童鞋想要一个穿着校服裤子、正装上衣外露的底裤怎么办?StudentWithSchoolUniform、StudentWithFormalWear、StudentWithNaked、StudentWithSchoolUniformAndOutSideUnderWear..................绵绵无尽的类~~~累!是的,如果这样就造成类爆炸了,需求增加,类就不断的增加,整个系统的维护难度可想而知。

      所以这时候,装饰者模式就可以发挥它的作用了,底裤、正装、校服、鞋子、眼镜等等都是具体的装饰者,学生是具体的被装饰的对象,被装饰的对象和装饰者的抽象类都继承者同一个父类。为学生穿上不同的服装,其实就是使用装饰者类(服装)包裹被装饰者类(学生),形象的说这是一个穿衣的过程。

    类和接口

    • Component(被装饰对象基类,对应例子的Person类)
    • ConcreteComponent(具体被装饰对象,对应例子的Student类)
    • Decorator(装饰者基类,对应例子的Costume)
    • ContreteDecorator(具体的装饰者类,对应例子的Pants、Shirt等)

    例子

    图2 

    Person.php

     1 <?php
     2 
     3 /**
     4 *    Person.php
     5 *   被装饰基类
     6 **/
     7     abstract class Person{
     8 
     9         public abstract function show();
    10 
    11     }
    View Code

    Student.php

     1 <?php
     2 
     3 /**
     4 *    Student.php
     5 *    具体被装饰对象
     6 **/
     7     class Student extends Person{
     8 
     9         private $name;
    10 
    11         public function __construct($name){
    12             $this->name = $name;
    13         }
    14 
    15         public function show(){
    16             echo '我是学生',$this->name;
    17         }
    18     }
    View Code

    Costume.php

     1 <?php
     2 
     3 /**
     4 *    Costume.php
     5 *    装饰者基类
     6 **/
     7     abstract class Costume extends Person{
     8     
     9 
    10     }
    View Code

    Shirt.php

     1 <?php
     2 
     3 /**
     4 *    Shirt.php
     5 *    具体的装饰者类
     6 **/
     7     class Shirt extends Costume{
     8 
     9         private $person;
    10 
    11         public function __construct(Person $person){
    12 
    13             $this->person = $person;
    14 
    15         }
    16 
    17         public function show(){
    18 
    19             echo $this->person->show(),',穿着衬衫';
    20         }
    21 
    22     }
    View Code

    Pants.php

     1 <?php
     2 
     3 /**
     4 *    Pants.php
     5 **/
     6     class Pants extends Costume{
     7 
     8         private $person;
     9 
    10         public function __construct(Person $person){
    11 
    12             $this->person = $person;
    13 
    14         }
    15 
    16         public function show(){
    17 
    18             echo $this->person->show(),',穿着裤子';
    19         }
    20 
    21     }
    View Code

    Glasses.php

     1 <?php
     2 
     3 /**
     4 *    Glasses.php
     5 **/
     6     class Glasses extends Costume{
     7 
     8         private $person;
     9 
    10         public function __construct(Person $person){
    11 
    12             $this->person = $person;
    13 
    14         }
    15 
    16         public function show(){
    17 
    18             echo $this->person->show(),',带着眼镜';
    19         }
    20 
    21     }
    View Code

    UnderWear.php

     1 <?php
     2 
     3 /**
     4 *    UnderWear.php
     5 **/
     6     class UnderWear extends Costume{
     7 
     8         private $person;
     9 
    10         public function __construct(Person $person){
    11 
    12             $this->person = $person;
    13 
    14         }
    15 
    16         public function show(){
    17 
    18             echo $this->person->show(),',穿着DK';
    19         }
    20 
    21     }
    View Code

    Client.php

     1 <?php
     2 
     3     require_once 'Person.php';
     4     require_once 'Costume.php';
     5     require_once 'Student.php';
     6     require_once 'UnderWear.php';
     7     require_once 'Shirt.php';
     8     require_once 'Pants.php';
     9     require_once 'Glasses.php';
    10 
    11     // Student继承Person
    12     $jc = new Student('JC');
    13     $jc->show();   // 我是学生JC
    14     echo '<br>';
    15 
    16     // 用UnderWear类装饰Person
    17     $underwear = new UnderWear($jc);
    18     $underwear->show();  // 我是学生JC,穿着DK
    19     echo '<br>';
    20 
    21     // 再用Pants类装饰Person
    22     $pants = new Pants($underwear);
    23     $pants->show();   // 我是学生JC,穿着DK,穿着裤子
    24     echo '<br>';
    25 
    26     // 再用Shirt类装饰Person
    27     $shirt = new Shirt($pants);
    28     $shirt->show();  // 我是学生JC,穿着DK,穿着裤子,穿着衬衫
    29     echo '<br>';
    30 
    31     // 再用Glasses类装饰Person
    32     $glasses = new Glasses($shirt);
    33     $glasses->show();  // 我是学生JC,穿着DK,穿着裤子,穿着衬衫,带着眼镜
    34     echo '<br>';

    图3 输出结果截图

    Symfony2 EventDispatch 组件对装饰者模式的应用

     

    图4 Symfony2 EventDispatch组件使用装饰模式

    图5 Framework配置EventDispatcher

     

    • SymfonyComponentEventDispatcherEventDispatcherInterface 是被装饰的接口
    • SymfonyComponentEventDispatcherEventDispatcher 和 SymfonyComponentEventDispatcherContainerAwareEventDispatcher 是被装饰的具体对象
    • SymfonyComponentEventDispatcherDebugTraceableEventDispatcherInterface 装饰者接口
    • SymfonyComponentEventDispatcherDebugTraceableEventDispatcher 装饰者基类
    • SymfonyComponentHttpKernelDebugTraceableEventDispatcher 具体的装饰者对象

      具体装饰者对象SymfonyComponentHttpKernelDebugTraceableEventDispatcher::dispatch()方法,核心依旧是调用被装饰的具体对象SymfonyComponentEventDispatcherEventDispatcher::dispatch()方法进行工作,但是装饰者对象SymfonyComponentHttpKernelDebugTraceableEventDispatcher::dispatch()方法添加了相应的功能,例如在调用SymfonyComponentEventDispatcherEventDispatcher::dispatch()方法前后分别调用了preProcess()、preDispatch()和postDispatch()、postProcess():

     1     /**
     2      * {@inheritdoc}
     3      */
     4     public function dispatch($eventName, Event $event = null)
     5     {
     6         if (null === $event) {
     7             $event = new Event();
     8         }
     9 
    10         // 装饰者对象增加的功能
    11         $this->preProcess($eventName);
    12         $this->preDispatch($eventName, $event);
    13 
    14         $e = $this->stopwatch->start($eventName, 'section');
    15 
    16         // 核心依旧是调用被装饰的具体对象SymfonyComponentEventDispatcherEventDispatcher::dispatch()方法
    17         $this->dispatcher->dispatch($eventName, $event);
    18 
    19         if ($e->isStarted()) {
    20             $e->stop();
    21         }
    22 
    23         // 装饰者对象增加的功能
    24         $this->postDispatch($eventName, $event);
    25         $this->postProcess($eventName);
    26 
    27         return $event;
    28     }

    优点

    1.  通过组合而非继承的方式,实现了动态扩展对象的功能的能力。
    2. 有效避免了使用继承的方式扩展对象功能而带来的灵活性差,子类无限制扩张的问题。
    3. 充分利用了继承和组合的长处和短处,在灵活性和扩展性之间找到完美的平衡点。
    4.  装饰者和被装饰者之间虽然都是同一类型,但是它们彼此是完全独立并可以各自独立任意改变的。
    5. 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。

    缺点

    1. 装饰链不能过长,否则会影响效率。
    2. 只在必要的时候使用装饰者模式,否则会提高程序的复杂性,增加系统维护难度。
    3. 装饰者对象和被装饰者对象都继承Component,如果Component内部发生变化,所有的子类都要改变。
  • 相关阅读:
    zip 中文文件夹为空问题
    webview长按文本区域不显示文字放大镜等方法
    crash
    精疲力尽先生的造访
    告别忙碌的2017,迎来更加忙碌的2018
    传说中的59分!!
    为什么我一定吵不过女人?
    人挪活!
    低谷时,请读书!
    java小入门的感觉
  • 原文地址:https://www.cnblogs.com/szuyuan/p/4123973.html
Copyright © 2011-2022 走看看