挖了设计模式这个坑,得继续填上。继续设计模式之路。这次讨论的模式,是
装饰者模式,有时也叫包装者(Wrapper),主要用于静态或动态地为一个特定的对象增加新的特性,而不影响这个对象的类(allows behavior to be added to an individual object, either statically or dynamically, without affecting the behavior of other objects from the same class)。
装饰者模式,主要用处是,灵活方便地增加特性到特定的对象上。请看下面的例子:
1 /** 2 * Coffee interface defines the functionality of Coffee implemented by decorator 3 * @author YYC 4 * 5 */ 6 public interface ICoffee { 7 8 double getCost(); 9 10 String getIngredients(); 11 12 } 13 14 15 /** 16 * extension of a simple coffee without any extra ingredients 17 * @author YYC 18 * 19 */ 20 public class SimpleCoffee implements ICoffee{ 21 22 public double getCost() { 23 return 1; 24 } 25 26 public String getIngredients() { 27 return "Coffee"; 28 } 29 30 } 31 32 33 /** 34 * abstract decorator class - note that it implement Coffee interface 35 * @author YYC 36 * 37 */ 38 public abstract class CoffeDecorator implements ICoffee { 39 40 protected final ICoffee decoratedCoffee; 41 protected String ingredientSeparator = ","; 42 43 public CoffeDecorator(ICoffee decoratedCoffee) { 44 this.decoratedCoffee = decoratedCoffee; 45 } 46 47 public double getCost(){ 48 return decoratedCoffee.getCost(); 49 } 50 51 public String getIngredients(){ 52 return decoratedCoffee.getIngredients(); 53 } 54 55 }
首先对于装饰者模式而已,一个公共的接口是必须的,在这里是ICoffee,代表咖啡的抽象接口。然后需要有一个简单的实现类以及一个装饰者的抽象类,作为具体装饰者的父类。接下来的是具体的装饰者类:
1 /** 2 * Decorator Milk that mixes milk with coffee 3 * @author YYC 4 * 5 */ 6 public class Milk extends CoffeDecorator { 7 8 public Milk(ICoffee decoratedCoffee) { 9 super(decoratedCoffee); 10 } 11 12 public double getCost() { 13 return super.getCost() + 0.5; 14 } 15 16 public String getIngredients() { 17 return super.getIngredients() + ingredientSeparator + "Milk"; 18 } 19 20 } 21 22 23 /** 24 * @author YYC 25 * Decorator Sprinkles that mixes sprinkles with coffee 26 */ 27 public class Sprinkles extends CoffeDecorator { 28 29 public Sprinkles(ICoffee decoratedCoffee) { 30 super(decoratedCoffee); 31 } 32 33 public double getCost() { 34 return super.getCost() + 1.2; 35 } 36 37 public String getIngredients() { 38 return super.getIngredients() + ingredientSeparator + "Sprinkles"; 39 } 40 41 }
具体的装饰者类,继承抽象装饰者类,并具体实现抽象装饰者类的方法,达到将新的特性(milk/sprinkles)加到原来的类(coffee)的目的。
public class Main { public static void main(String[] args) { ICoffee c = new SimpleCoffee(); System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients()); c = new Milk(c); System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients()); c = new SimpleCoffee(); c = new Sprinkles(c); System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients()); c=new SimpleCoffee(); c = new Milk(new Sprinkles(c)); System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients()); } } /* * output: * Cost: 1.0; Ingredients: Coffee * Cost: 1.5; Ingredients: Coffee,Milk * Cost: 2.2; Ingredients: Coffee,Sprinkles * Cost: 2.7; Ingredients: Coffee,Sprinkles,Milk */
抽象类理解起来并不困难,而且相当实用,很多时候比创建子类更加灵活。在Java里java.io.BufferedReader/FileReader/Reader都有使用这个模式。
以下情况使用Decorator模式
1. 需要扩展一个类的功能,或给一个类添加附加职责。
2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
优点:
1. Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。
2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
缺点:
1. 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
3. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。
参考:
http://javapapers.com/design-patterns/decorator-pattern/
http://www.cnblogs.com/god_bless_you/archive/2010/06/10/1755212.html