设计模式之装饰者模式 定义装饰者模式 装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
设计原则 类应该对扩展开发,对修改关闭
装饰者模式类图
用装饰者来设计我们的饮料 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public abstract class Beverage { protected String description = "Unknown Beverage" ; public String getDescription () { return description; } public abstract double cost () ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 public abstract class CondimentDecorator extends Beverage { @Override public abstract String getDescription () ; }
设计饮料的对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class Espresso extends Beverage { public Espresso () { super .description = "Espresso" ; } @Override public double cost () { return 1.99 ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class HouseBlend extends Beverage { public HouseBlend () { super .description = "House Blend Coffee" ; } @Override public double cost () { return 0.89 ; } }
设计调料的对象 我们已经完成了抽象组件(Beverage
),有了具体组件(HouseBlend
),也有了抽象装饰者(CondimentDecorator
)。现在就来实现具体装饰者。先从摩卡下手:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class Mocha extends CondimentDecorator { private final Beverage beverage; public Mocha (Beverage beverage) { this .beverage = beverage; } @Override public String getDescription () { return beverage.getDescription() + ", Mocha" ; } @Override public double cost () { return 0.20 + beverage.cost(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class Whip extends CondimentDecorator { private final Beverage beverage; public Whip (Beverage beverage) { this .beverage = beverage; } @Override public double cost () { return 0.5 + beverage.cost(); } @Override public String getDescription () { return beverage.getDescription() +", Whip" ; } }
测试结果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class StarbuzzCoffee { public static void main (String[] args) { Beverage beverage = new Espresso (); System.out.println(beverage.getDescription() + " $" + beverage.cost()); Beverage beverage2 = new DarkRoast (); beverage2 = new Mocha (beverage2); beverage2 = new Mocha (beverage2); beverage2 = new Whip (beverage2); System.out.println(beverage2.getDescription() + " $" + beverage2.cost()); } }
来看看结果 1 2 Espresso $1.99 Dark Roast , Mocha , Mocha , Whip $1.79
让我们来看看Java I/O里的装饰者 装饰的 java.io 类
编写自己的Java I/O 装饰者 编写一个装饰者,把输入流内的所有大写字符转成小写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package com.design.decorator.io;import java.io.FilterInputStream;import java.io.IOException;import java.io.InputStream;public class LowerCaseInputStream extends FilterInputStream { protected LowerCaseInputStream (InputStream in) { super (in); } @Override public int read () throws IOException { int c = super .read(); return c == -1 ? c : Character.toLowerCase((char ) c); } @Override public int read (byte [] b, int off, int len) throws IOException { int result = super .read(b, off, len); for (int i = off; i < off + result; i++) { b[i] = (byte ) Character.toLowerCase((char ) b[i]); } return result; } }
测试我们新的Java I/O装饰者 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class InputTest { public static void main (String[] args) throws IOException { InputStream in = null ; try { in = new LowerCaseInputStream (new BufferedInputStream (System.in)); int c; while ((c = in.read()) > 0 ) { System.out.print((char ) c); } } catch (IOException e) { e.printStackTrace(); } finally { if (in != null ) { in.close(); } } } }
1 2 3 4 5 6 7 运行结果: HELLO hello HI hi HELLO WORLD hello world
总结
继承属于扩展形式之一,但不见得达到弹性设计的最佳方式
在我们的设计中,应该允许行为可以被扩展,而无须修改现有的代码
组合和委托可用于在运行时动态地加上新的行为
除了继承,装饰者模式也可以让我们扩展行为
装饰者模式意味着一群装饰者类,这些类用来包装具体组件
装饰者类反映出被装饰的组件类型
装饰者可以在被修饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的目的
你可以用无所个装饰者包装一个组件
装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型
装饰者会导致设计中出现许多小装饰对象,如果过度使用,会让程序变得很复杂