zoukankan      html  css  js  c++  java
  • 装饰者模式(Decorator Pattern)

    装饰者模式

    MM们要过生日了 ,怎么也得表示下吧。最起码先送个蛋糕。蛋糕多种多样了。巧克力,冰淇淋,奶油等等。这都是基本的了 ,再加点额外的装饰,如蛋糕里放点花。放贺卡。放点干果吃着更香等等。看看我是如何设计的。
     
          我想既然是蛋糕,那我就把蛋糕作为一个抽象类,剩下的蛋糕子类型来继承它,每个子类都有吃该蛋糕的感觉 ^_^,看起来真的不错。蛋糕的子类分别是奶酪蛋糕,巧克力蛋糕,冰淇淋蛋糕,插花的冰淇淋蛋糕,放贺卡的冰淇淋蛋糕。某个MM的生日蛋糕喜欢带花的冰淇 淋蛋糕。还好我早有准备。但是有几次失策了。。她们要的蛋糕我这都没有。比如带鲜花的巧克力蛋糕。带果仁的牛奶蛋糕。带鲜花带果仁的蛋糕。。。。那我还要 继续添加蛋糕的子类。。问题出现了。这样会造成大量的蛋糕子类 。真是噩梦啊。

    那么我要好好思考这个问题了。发现了刚才的设计确实有问题。。发现了真正的要关注的主体是蛋糕。。而贺卡,花,果仁等等只不过是装饰 的作用。

    思路来了。蛋糕作为主体,其他的东西都加到蛋糕上。MM要啥我就加啥呗。呵呵。

    到现在我们要明确的是:

    • 蛋糕是主体。
    • 花,贺卡,果仁等等是装饰者。
    • 可以用装饰者包装蛋糕。

    来看看什么是装饰器模式吧:

    动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

    • Component:抽象出的主体对象。
    • ConcreteComponent:是要动态扩展的对象,它继承自Component.
    • Decorator:是装饰器的接口。(这里的接口并不是指java的interface)。
    • ConcreteDecoratorA:实现Decorator的类,包含了一个Component引用,这样就可以扩展Component的方法了。

    说完理论了。可能还一头雾水吧。。。还是接着蛋糕的例子继续说。先看图吧。


    基本符合了上面所提到的装饰者模式的框架结构了。再看看代码:

    Cake

    Java代码  
    1. package decorator.demo;  
    2.   
    3. /** 
    4.  * 蛋糕基类 
    5.  * @author Nicholas 
    6.  * 
    7.  */  
    8. public abstract class Cake {  
    9.     String remark = "蛋糕";  
    10.     public String getRemark() {  
    11.         return remark;  
    12.     }  
    13.     public abstract String getImpression();//用来描述吃蛋糕的感觉。。。。  
    14. }  

     Cake是个抽象类,它已经实现了getRemark的方法。但没有实现getImpression.这个方法必须被子类实现。

    再看看装饰器的抽象类

    OtherDecorator

    Java代码  
    1. package decorator.demo;  
    2.   
    3. /** 
    4.  * 其他用来添加蛋糕的东西 
    5.  * @author Nicholas 
    6.  * 
    7.  */  
    8. public abstract class OtherDecorator extends Cake{  
    9.     Cake cake;  
    10.     /** 
    11.      * 引用一个Cake. 
    12.      * 让被装饰者进入装饰者之中。这里用的是构造方法注入。 
    13.      * 这样就可以调用Cake实例的方法了。 
    14.      * @param cake 
    15.      */  
    16.     public OtherDecorator(Cake cake){  
    17.         this.cake=cake;  
    18.     }  
    19.     /** 
    20.      * 让装饰器的子类都去实现getRemark方法。业务需要每个装饰器都要有描述。 
    21.      */  
    22.     public abstract String getRemark();  
    23. }  

    下面让我们实现一个蛋糕吧。^_^。。

    Java代码  
    1. package decorator.demo;  
    2. /** 
    3.  * 乳酪蛋糕 
    4.  * @author Nicholas 
    5.  * 
    6.  */  
    7. public class CheeseCake extends Cake{  
    8.     /** 
    9.      * 乳酪蛋糕的构造方法 
    10.      */  
    11.     public CheeseCake(){  
    12.         super.remark="乳酪蛋糕";//修改乳酪蛋糕的描述。  
    13.     }  
    14.   
    15.     /** 
    16.      * 实现了Cake抽象类的getImpression 
    17.      * 吃乳酪蛋糕的感觉。。 
    18.      */  
    19.     public String getImpression() {  
    20.         return "香甜感受";  
    21.     }  
    22.   
    23. }  

    其他实现Cake的类就不列出了,道理是一样的。

    下面我们要开始实现具体的装饰器了。

    Java代码  
    1. package decorator.demo;  
    2.   
    3. /** 
    4.  * 给蛋糕添加的花 
    5.  * @author Nicholas 
    6.  * 
    7.  */  
    8. public class FlowerDecorator extends OtherDecorator{  
    9.       
    10.     /** 
    11.      * 构造函数 
    12.      * 传入一个cake实例,也就是前面所实现的Cake的子类,如奶酪蛋糕,巧克力蛋糕等等。 
    13.      * @param cake 
    14.      */  
    15.     public FlowerDecorator(Cake cake){  
    16.         super(cake);//调用父类的构造方法,可以获取Cake的实例了。就可以调用Cake实例的方法.  
    17.         super.remark="一朵玫瑰花";  
    18.     }  
    19.       
    20.     /** 
    21.      * 实现了装饰器抽象类的getImpression方法。 
    22.      */  
    23.     public String getImpression() {  
    24.         //这是重点。我们通过构造方法传入的cake实例。对cake进行了装饰,增加了新的功能。  
    25.         return cake.getImpression()+","+"看到一朵花真是happy";  
    26.     }  
    27.   
    28.     public String getRemark() {  
    29.         return cake.getRemark()+"+"+super.remark;  
    30.     }  
    31. }  

     到现在终于大功告成了。。这样方便了很多,可以通过装饰器生成很多种类的蛋糕。

    Java代码  
    1. package decorator.demo;  
    2.   
    3. public class MyGirlB {  
    4.     public static void main(String[] args){  
    5.         //用果仁,花包装巧克力蛋糕。  
    6.         Cake nutsFlowerChocolateCake = new NutsDecorator(new FlowerDecorator(new ChocolateCake()));  
    7.         System.out.println("remark "+nutsFlowerChocolateCake.getRemark());  
    8.         //吃蛋糕的感受已经发生了改变。  
    9.         System.out.println("impression "+nutsFlowerChocolateCake.getImpression());  
    10.     }  
    11. }  

    这个模式的缺点也挺明显的 ,看看如下图片

    为了扩展cake的功能,加入了许多的装饰类。。当然用户也可以继承OtherDecorator来继续扩展。但是对API使用者是个困扰。。所以API要说明哪些类是用来包装的。

    转自:http://www.iteye.com/topic/335521

  • 相关阅读:
    sql 语句系列(加减乘除与平均)[八百章之第十四章]
    并发系列64章(并发概要)第一章
    redis 一百二十篇(简单介绍)之第一篇
    sql 语句系列(分割ip)[八百章之第十四章]
    sql 语句系列(字符串之裂开)[八百章之第十三章]
    sql 语句系列(字符串之父与子之间)[八百章之第十二章]
    sql 语句系列(字符串的遍历嵌入删除与统计)[八百章之第十一章]
    sql 语句系列(用魔法打败魔法)[八百章之第十章]
    sql 语句系列(列举非索引外键)[八百章之第九章]
    sql 语句系列(列举系列)[八百章之第八章]
  • 原文地址:https://www.cnblogs.com/hnrainll/p/2305576.html
Copyright © 2011-2022 走看看