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

什么是装饰者模式?

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

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

新的设计原则

对扩展开发,对修改关闭

写一写要点

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




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

怎么开始?
写下星巴兹的代码:
[java]  view plain copy
  1. package decoratorPattern;  
  2. /** 
  3.  * 
  4.  * @author mmmm
  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
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 
  5.  * @author mmmm
  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
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  *  
  5.  * @author mmmm 
  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
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 
  5.  * @author mmmm 
  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
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 
  5.  * @author mmmm 
  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
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 
  5.  * @author mmmm
  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
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 
  5.  * @author mmmm 
  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
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 
  5.  * @author mmmm
  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
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  *  
  5.  * @author mmmm 
  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
  1. package decoratorPattern;  
  2.   
  3. /** 
  4.  * 测试类,供应咖啡 
  5.  * @author mmmm 
  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
  1. Espresso $1.99  
  2. DarkRoast, Mocha, Mocha,Whip $1.49  
  3. House Blend Coffee,Soy, Mocha,Whip $1.34  


刚开始的时候已经说过Java中使用装饰者模式的I/O
下面就扩展一下它的行为:将大写字符转换为小写字符
[java]  view plain copy
  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
  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
  1. i know the decorator pattern  

ok,装饰者模式就是这样子啦,搞清楚装饰者和被装饰者之间的关系,也没啥不好理解的。下一个设计模式:工厂模式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值