装饰模式


目录(?) [+]
  1. 设计模式学习--装饰者模式Decorator Pattern
    1. 什么是装饰者模式
    2. 其实我们用Java IO的时候已经用到过了只是可能不知道这就是设计模式在后面有一个设计自己的装饰者模式再介绍吧
    3. 新的设计原则
    4. 写一写要点
    5. 装饰者模式例子星巴兹咖啡

设计模式学习--装饰者模式(Decorator Pattern)


什么是装饰者模式?

其实我们用Java I/O的时候已经用到过了,只是可能不知道这就是设计模式,在后面有一个设计自己的装饰者模式,再介绍吧。

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

新的设计原则

对扩展开发,对修改关闭

写一写要点

1. 继承属于扩展形式之一,但不见得达到弹性设计的最佳方式。
2. 在我们的设计中,应该允许行为可以被扩展,而无须修改现有的代码。
3. 组合和委托可用于在运行时动态加上新的行为。
4. 除了继承,装饰者模式也可以让我们扩展行为。
5. 装饰者模式意味着一群装饰者类,这些类用来包装具体组件。
6. 装饰者类反映出被装饰的组件类型(事实上,他们具有相同的类型,都经过接口或继承实现)
7. 装饰者可以在被装饰者的行为与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的目的。
8. 你可以用无数个装饰者包装一个组件。
9. 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。
10. 装饰者会导致设计中出现许多的小对象,如果过度使用,会让程序变得很复杂。




装饰者模式例子:星巴兹咖啡

怎么开始?
写下星巴兹的代码:
[java] view plain copy print ?
  1. package decoratorPattern;  
  2. /** 
  3.  * 2013/5/19 
  4.  * @author wwj 
  5.  * 饮料抽象类 
  6.  */  
  7. public abstract class Beverage {  
  8.     String description = "Unknown Beverage"//饮料描述  
  9.       
  10.     public String getDescription() {    //得到饮料描述  
  11.         return description;  
  12.     }  
  13.       
  14.     public abstract double cost();  //抽象方法,用于计算饮料价格  
  15. }  


[java] view plain copy print ?
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 2013/5/19 
  5.  * @author wwj 
  6.  * 调料抽象类:代表装饰者 
  7.  */  
  8. public abstract class CondimentDecorator extends Beverage {  
  9.   
  10.     @Override  
  11.     public double cost() {  
  12.         return 0;  
  13.     }  
  14.       
  15.     /** 
  16.      * 所有的调料装饰者都必须重新实现getDescription()方法。 
  17.      */  
  18.     public abstract String getDescription();  
  19.   
  20. }  


写饮料的代码:
这里有四种:Epresso、HouseBlend、DarkRoast、Decat

[java] view plain copy print ?
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 2013/5/19 
  5.  * @author wwj 
  6.  * 浓缩咖啡,一种饮料 
  7.  */  
  8. public class Espresso extends Beverage {  
  9.     public Espresso() {  
  10.         description = "Espresso";  
  11.     }  
  12.       
  13.     @Override  
  14.     public double cost() {  
  15.         return 1.99;  
  16.     }  
  17.   
  18. }  

[java] view plain copy print ?
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 2013/5/19 
  5.  * @author wwj 
  6.  * 综合饮料 
  7.  */  
  8. public class HouseBlend extends Beverage {  
  9.     public HouseBlend(){  
  10.         description = "House Blend Coffee";  
  11.     }  
  12.       
  13.     @Override  
  14.     public double cost() {  
  15.         return .89;  
  16.     }  
  17.   
  18. }  

[java] view plain copy print ?
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 2013/5/19 
  5.  * @author wwj 
  6.  * 深培咖啡 
  7.  */  
  8. public class DarkRoast extends Beverage {  
  9.     public DarkRoast(){  
  10.         description = "DarkRoast";  
  11.     }  
  12.     @Override  
  13.     public double cost() {  
  14.         return .99;  
  15.     }  
  16.   
  17. }  

[java] view plain copy print ?
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 2013/5/19 
  5.  * @author wwj 
  6.  * 低咖啡因 
  7.  */  
  8. public class Decat extends Beverage {  
  9.     public Decat(){  
  10.         description = "Decat";  
  11.     }  
  12.     @Override  
  13.     public double cost() {  
  14.         return 1.05;  
  15.     }  
  16.   
  17. }  


写调料的代码
这里有三种调料:Mocha、Soy、Whip
[java] view plain copy print ?
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 2013/5/19 
  5.  * @author wwj 
  6.  * 具体装饰者:摩卡 
  7.  */  
  8. public class Mocha extends CondimentDecorator {  
  9.     //定义一个实例变量记录饮料,也就是被装饰者  
  10.     Beverage beverage;  
  11.       
  12.     /** 
  13.      * 用来把被装饰者记录到实例变量中去 
  14.      * @param beverage 
  15.      */  
  16.     public Mocha(Beverage beverage) {  
  17.         this.beverage = beverage;  
  18.     }  
  19.   
  20.       
  21.     /** 
  22.      * 这里利用委托的做法,得到一个叙述,然后在其后加上附加的叙述 
  23.      */  
  24.     @Override  
  25.     public String getDescription() {  
  26.         return beverage.getDescription() + ", Mocha";  
  27.     }  
  28.       
  29.     /** 
  30.      * 要计算Mocha饮料的价钱。首先把调用委托给被装饰对象,以计算价钱,然后再加上Mocha的价钱,得到最后结果 
  31.      */  
  32.     public double cost() {  
  33.         return .20 + beverage.cost();  
  34.     }  
  35. }  

[java] view plain copy print ?
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 2013/5/19 
  5.  * @author wwj 
  6.  * 豆浆,一种配料 
  7.  */  
  8. public class Soy extends CondimentDecorator {  
  9.     Beverage beverage;  
  10.       
  11.       
  12.     public Soy(Beverage beverage) {  
  13.         this.beverage = beverage;  
  14.     }  
  15.   
  16.   
  17.     @Override  
  18.     public String getDescription() {  
  19.         return beverage.getDescription() + ",Soy";  
  20.     }  
  21.       
  22.     public double cost() {  
  23.         return .15 + beverage.cost();  
  24.     }  
  25.   
  26. }  

[java] view plain copy print ?
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 2013/5/19 
  5.  * @author wwj 
  6.  * 奶泡,一种配料 
  7.  */  
  8. public class Whip extends CondimentDecorator {  
  9.     Beverage beverage;  
  10.       
  11.       
  12.     public Whip(Beverage beverage) {  
  13.         this.beverage = beverage;  
  14.     }  
  15.   
  16.   
  17.     @Override  
  18.     public String getDescription() {  
  19.         return beverage.getDescription() + ",Whip";  
  20.     }  
  21.       
  22.     public double cost() {  
  23.         return .10 + beverage.cost();  
  24.     }  
  25.   
  26. }  

现在可以供应咖啡了
[java] view plain copy print ?
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 测试类,供应咖啡 
  5.  * @author wwj 
  6.  * 
  7.  */  
  8. public class StarbuzzCoffee {  
  9.   
  10.     public static void main(String[] args) {  
  11.         //订一杯Espresso,不需要调料,打印出它的描述与价钱  
  12.         Beverage beverage = new Espresso();  
  13.         System.out.println(beverage.getDescription() + " $" + beverage.cost());  
  14.           
  15.         Beverage beverage2 = new DarkRoast();  
  16.         beverage2 = new Mocha(beverage2);   //用Mocha装饰它  
  17.         beverage2 = new Mocha(beverage2);   //用第二个Mocha装饰它  
  18.         beverage2 = new Whip(beverage2);    //用Whip装饰它  
  19.         System.out.println(beverage2.getDescription() + " $" + beverage2.cost());  
  20.           
  21.           
  22.         Beverage beverage3 = new HouseBlend();  
  23.         beverage3 = new Soy(beverage3);  
  24.         beverage3 = new Mocha(beverage3);  
  25.         beverage3 = new Whip(beverage3);  
  26.         System.out.println(beverage3.getDescription() + " $" + beverage3.cost());  
  27.     }  
  28. }  
实验结果如下:

[plain] view plain copy print ?
  1. Espresso $1.99  
  2. DarkRoast, Mocha, Mocha,Whip $1.49  
  3. House Blend Coffee,Soy, Mocha,Whip $1.34  

如果觉得看得不够爽,买办HeadFirst设计模式吧,就算小巫是新手也还是觉得这本书值得一卖,图文并茂,看起来不会累。


刚开始的时候已经说过Java中使用装饰者模式的I/O
下面就扩展一下它的行为:将大写字符转换为小写字符
[java] view plain copy print ?
  1. package javaIo;  
  2.   
  3. import java.io.FilterInputStream;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6.   
  7. /* 
  8.  * 编写自己的Java I/O装饰者 
  9.  */  
  10. public class LowerCaseInputStream extends FilterInputStream {  
  11.   
  12.     protected LowerCaseInputStream(InputStream in) {  
  13.         super(in);  
  14.     }  
  15.     /** 
  16.      * 针对字节 
  17.      */  
  18.     public int read() throws IOException {  
  19.         int c = super.read();  
  20.         return (c == -1 ? c : Character.toLowerCase((char) c));  
  21.     }  
  22.       
  23.     /** 
  24.      * 针对字节数组 
  25.      */  
  26.     public int read(byte[] b, int offset, int len) throws IOException {  
  27.         int result = super.read(b, offset, len);  
  28.         for(int i = offset; i < offset + result; i++) {  
  29.             b[i] = (byte) Character.toLowerCase((char)b[i]);  
  30.         }  
  31.         return result;  
  32.     }  
  33.   
  34. }  


[java] view plain copy print ?
  1. package javaIo;  
  2.   
  3. import java.io.BufferedInputStream;  
  4. import java.io.FileInputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7.   
  8. public class InputTest {  
  9.     public static void main(String[] args) throws IOException{  
  10.         int c;  
  11.         try {  
  12.             //设置FileInputStream,先用BufferedInputStream装饰它,再用我们崭新的  
  13.             //LowerCaseInputStream过滤器装饰它  
  14.             InputStream in =  
  15.                 new LowerCaseInputStream(  
  16.                         new BufferedInputStream(new FileInputStream("D:/test.txt")));  
  17.             while((c = in.read()) >= 0) {  
  18.                 System.out.print((char)c);  
  19.             }  
  20.             in.close();  
  21.         } catch (IOException e) {  
  22.             e.printStackTrace();  
  23.         }  
  24.     }  
  25. }  

测试结果:
[plain] view plain copy print ?
  1. i know the decorator pattern  

ok,装饰者模式就是这样子啦,搞清楚装饰者和被装饰者之间的关系,也没啥不好理解的。下一个设计模式:工厂模式,比较常用的一个模式。今天是星期日,宝贵的周末时间就要没了,可能就不会想这两天那么频繁地发表博客了,不过有空一定会继续学习的。


你可能感兴趣的:(装饰模式)