23种设计模式之四(装饰者模式)

Posted 淼淼之森

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了23种设计模式之四(装饰者模式)相关的知识,希望对你有一定的参考价值。

装饰者模式:(动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性)

 其别名为包装器(Wrapper);装饰模式是一种对象结构模式。

设计原则:对扩展开放、对修改关闭,这句话体现在我如果想扩展被装饰者类的行为,无须修改装饰者抽象类;只需继承装饰者抽象类,实现额外的一些装饰或者叫行为即可对被装饰者进行包装。

所以:扩展体现在继承、修改体现在子类中,而不是具体的抽象类,这充分体现了依赖倒置原则。

 

举例:

咖啡馆订单项目:
1)、咖啡种类:Espresso、ShortBlack、LongBlack、Decaf
2)、调料:Milk、Soy、Chocolate
3)、扩展性好、改动方便、维护方便

就如同调制一杯饮品:

  主体:黑咖啡、浓缩黑咖啡、无咖啡因咖啡、意式浓缩咖啡

  包装:牛奶、巧克力、豆浆

 

 超类(被装饰者):

 1 package com.java.jikexueyuan.coffeebar;
 2 
 3 public abstract class Drink {
 4     public String description="";
 5     private float price=0f;;
 6     
 7     
 8     public void setDescription(String description)
 9     {
10         this.description=description;
11     }
12     
13     public String getDescription()
14     {
15         return description+"-"+this.getPrice();
16     }
17     public float getPrice()
18     {
19         return price;
20     }
21     public void setPrice(float price)
22     {
23         this.price=price;
24     }
25     public abstract float cost();
26     
27 }
Drink

 主体(被装饰者):

 1 package com.java.jikexueyuan.coffeebar.coffee;
 2 
 3 import com.java.jikexueyuan.coffeebar.Drink;
 4 
 5 //中间层:将各种咖啡共有的功能进行封装
 6 public  class Coffee extends Drink {
 7     @Override
 8     public float cost() {
 9         // TODO Auto-generated method stub
10         return super.getPrice();
11     }
12 }
Coffee
 1 package com.java.jikexueyuan.coffeebar.coffee;
 2 
 3 public class ShortBlack extends Coffee{
 4     
 5     public ShortBlack(){
 6         super.setDescription("ShortBlack");
 7         super.setPrice(5.0f);
 8     }
 9 
10 }
ShortBlack
 1 package com.java.jikexueyuan.coffeebar.coffee;
 2 
 3 public class LongBlack extends Coffee{
 4     
 5     public LongBlack(){
 6         super.setDescription("LongBlack");
 7         super.setPrice(6.0f);
 8     }
 9 
10 }
LongBlack
1 package com.java.jikexueyuan.coffeebar.coffee;
2 
3 public class Decaf extends Coffee {
4     public Decaf()    {
5         super.setDescription("Decaf");
6         super.setPrice(3.0f);
7     }
8 }
Decaf
 1 package com.java.jikexueyuan.coffeebar.coffee;
 2 
 3 public class Espresso extends Coffee{
 4     
 5     public Espresso(){
 6         super.setDescription("Espresso");
 7         super.setPrice(4.0f);
 8     }
 9 
10 }
Espresso

装饰者:

 1 package com.java.jikexueyuan.coffeebar.decorator;
 2 
 3 import com.java.jikexueyuan.coffeebar.Drink;
 4 
 5 //中间层:将各种调料的共有功能封装出来
 6 public  class Decorator extends Drink {
 7     private Drink Obj;
 8 
 9     public Decorator(Drink Obj){
10         this.Obj=Obj;
11     };
12     
13     
14     @Override
15     public float cost() {
16         return super.getPrice()+Obj.cost();
17     }
18 
19     @Override
20     public String getDescription(){
21         return super.description+"-"+super.getPrice()+"&&"+Obj.getDescription();
22     }
23     
24     }
Decorator
包装(装饰):
 1 package com.java.jikexueyuan.coffeebar.decorator;
 2 
 3 import com.java.jikexueyuan.coffeebar.Drink;
 4 
 5 public class Chocolate extends Decorator {
 6 
 7     public Chocolate(Drink Obj) {        
 8         super(Obj);
 9         // TODO Auto-generated constructor stub
10         super.setDescription("Chocolate");
11         super.setPrice(3.0f);
12     }
13 
14 }
Chocolate
 1 package com.java.jikexueyuan.coffeebar.decorator;
 2 
 3 import com.java.jikexueyuan.coffeebar.Drink;
 4 
 5 public class Milk extends Decorator {
 6 
 7     public Milk(Drink Obj) {        
 8         super(Obj);
 9         // TODO Auto-generated constructor stub
10         super.setDescription("Milk");
11         super.setPrice(2.0f);
12     }
13 
14 }
Milk
 1 package com.java.jikexueyuan.coffeebar.decorator;
 2 
 3 import com.java.jikexueyuan.coffeebar.Drink;
 4 
 5 public class Soy extends Decorator {
 6 
 7     public Soy(Drink Obj) {        
 8         super(Obj);
 9         // TODO Auto-generated constructor stub
10         super.setDescription("Soy");
11         super.setPrice(1.5f);
12     }
13 
14 }
Soy

测试:

 1 package com.java.jikexueyuan.coffeebar;
 2 
 3 import com.java.jikexueyuan.coffeebar.coffee.Decaf;
 4 import com.java.jikexueyuan.coffeebar.coffee.LongBlack;
 5 import com.java.jikexueyuan.coffeebar.decorator.Chocolate;
 6 import com.java.jikexueyuan.coffeebar.decorator.Milk;
 7 
 8 public class CoffeeBar {
 9 
10 
11     public static void main(String[] args) {
12         
13         Drink order;
14         order=new Decaf();
15         System.out.println("order1 price:"+order.cost());
16         System.out.println("order1 desc:"+order.getDescription());
17         
18         System.out.println("****************");
19         order=new LongBlack();
20         order=new Milk(order);
21         order=new Chocolate(order);
22         order=new Chocolate(order);
23         System.out.println("order2 price:"+order.cost());
24         System.out.println("order2 desc:"+order.getDescription());
25         
26     }
27 
28 
29 }
main
order1 price:3.0
order1 desc:Decaf-3.0
****************
order2 price:14.0
order2 desc:Chocolate-3.0&&Chocolate-3.0&&Milk-2.0&&LongBlack-6.0
运行结果:

 

 

Java内置装饰者:

2、编写自己的Java I/O装饰者:

 1 package com.java.jikexueyuan.myiodecorator;
 2 
 3 import java.io.FilterInputStream;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 
 7 public class UpperCaseInputStream extends FilterInputStream{
 8 
 9     protected UpperCaseInputStream(InputStream in) {
10         super(in);
11         // TODO Auto-generated constructor stub
12     }
13 
14     public int read() throws IOException
15     {
16         int c=super.read();
17         return c==-1?c:Character.toUpperCase((char)(c));
18     }
19     public int read(byte[] b,int offset,int len) throws IOException
20     {
21         int result=super.read(b,offset,len);
22         for(int i=0;i<result;i++)
23         {
24             b[i]=(byte)Character.toUpperCase((char)(b[i]));
25         }
26         
27         return result;
28     }
29 }
UpperCaseInputStream
 1 package com.java.jikexueyuan.myiodecorator;
 2 
 3 import java.io.BufferedInputStream;
 4 import java.io.FileInputStream;
 5 import java.io.FileNotFoundException;
 6 import java.io.IOException;
 7 import java.io.InputStream;
 8 
 9 public class InputTest {
10     public static void main(String[] args) {
11         int c;
12         try {
13             InputStream in = new UpperCaseInputStream(new BufferedInputStream(
14                     new FileInputStream("D:\\\\test\\\\test.txt")));
15             while((c=in.read())>=0)
16             {
17                 System.out.print((char)c);
18                 
19             }
20         } catch (IOException e) {
21             // TODO Auto-generated catch block
22             e.printStackTrace();
23         }
24 
25     }
26 }
main:
ZHE SHI CE SHI WEN JIAN !
运行结果:

 

 

注意:
一个装饰者类的接口必须与被装饰者的接口一致;
尽量保持具体装饰者类作为一个“轻”类,也就是说不要把太多的逻辑和状态放到具体装饰者类去实现;
优先使用组合、聚合原则,少用继承。

(参考:http://www.cnblogs.com/chenxing818/p/4705919.html或http://blog.csdn.net/jason0539/article/details/22713711)

 

优点:
装饰模式与类继承的目的都是扩展对象的功能,但是装饰模式可以提供比类继承更多的灵活性;
通过使用不同的具体装饰类以及这些装饰类的排列组合,开发者可以创造出很多不同行为的组合;
缺点:
这种比类继承更加灵活机动的特性,也同时意味着装饰模式比类继承更容易出错;
使用装饰模式增加了代码的复杂度。

 

 

应用场景:

1、在不影响其它对象情况下,以动态透明的方式给单个对象添加职责;

2、需要动态给一个对象添加功能,这些功能可以在动态的被撤销;

3、当不能采用类继承的方式进行扩展时。

  一种情况是可能有大量独立的扩展,每一种组合将产生大量的子类,使得子类数量呈爆炸性增长;

  另一种情况可以是因为类定义不能继承(final)或不能用于生成子类。

 

以上是关于23种设计模式之四(装饰者模式)的主要内容,如果未能解决你的问题,请参考以下文章

23种设计模式学习之装饰者模式

[23种设计模式]---装饰者模式

实践GoF的23种设计模式:装饰者模式

23种设计模式-装饰者模式

23种设计模式——装饰模式单一职责

23种设计模式简单总结