HeadFirst 设计模式学习笔记3--装饰模式

1.这个模式可以称为“给爱用继承的人一个全新的设计眼界”的模式。牵扯到第五个设计原则:“类应该对扩展开放,而对修改封闭”。但是要注意,遵循这一标准会带来更多层次上的抽象,增加代码的复杂度,所以并不是所有类都要这样设计。

2.文中举了一个为辛巴克咖啡馆写一个计算咖啡价格+调料价格的类,使用了装饰模式——动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。我们就拿这个计算咖啡价格的东西举例子。

3.在原来的设计中,都是继承与Beverage这个超类中,多一项咖啡+调料组合就多一个子类,最后造成类的爆炸。而使用装饰模式,我们希望用装饰器(这里的调料)一层层的包含被装饰的咖啡,最后达到通过调用最外层的装饰者的cost()方法就可以委托其内部计算计算价钱。我们针对这个目标,从代表饮品的Beverage类下手:

public abstract class Beverage { String description = "Unknown Beverage"; public String getDescription() { return description; } public abstract double cost(); }

我们将调料视为装饰器,这个装饰器超类为了能够将要被装饰的部分包起来,所以要继承自饮品这个超类:

public abstract class CondimentDecorator extends Beverage { public abstract String getDescription(); }

现在我们就构造一些饮品

public class Espresso extends Beverage { public Espresso() { description = "Espresso";//这个变量是继承而来 } public double cost() { return 1.99; } } public class HouseBlend extends Beverage { public HouseBlend() { description = "House Blend Coffee"; } public double cost() { return .89; } }

然后我们构建具体的装饰者,比如代表摩卡的Mocha类:

public class Mocha extends CondimentDecorator { Beverage beverage;//用一个实例变量记录饮品,然后通过构造函数将饮品记录在实例变量中完成装饰的过程。 public Mocha(Beverage beverage) { this.beverage = beverage; } public String getDescription() {//这两个方法都调用了被装饰部分的相关方法, return beverage.getDescription() + ", Mocha"; } public double cost() { return .20 + beverage.cost(); } }

现在我们测试一下这些代码,喝杯比较多样化的咖啡:

public class StarbuzzCoffee { public static void main(String args[]) { Beverage beverage = new Espresso(); System.out.println(beverage.getDescription() + " $" + beverage.cost()); Beverage beverage3 = new HouseBlend(); beverage3 = new Soy(beverage3);//一直针对抽象组建类型编程 beverage3 = new Mocha(beverage3); beverage3 = new Whip(beverage3); System.out.println(beverage3.getDescription() + " $" + beverage3.cost()); } }

4.总结一下装饰模式特点:

装饰者和被装饰对象有相同的超类型--都是来自Beverage这个类。
你可以用一个或多个装饰者包装一个对象--看看beverage3这个对象就知道了。
在任何需要被包装者的场合可以用装饰过的对象代替它--比如首先我们在咖啡上加豆浆,然后我们在加豆浆的咖啡上想再加摩卡的话,我们可以直接在这个加过豆浆的咖啡对象上加摩卡。
装饰者可以在所委托的被装饰者的行为上加上自己的行为,达到特定目的--getDescription和cost方法充分证明了这一点。
5.JDK中的装饰模式

最典型的就是IO系统了,比如BufferedInputStream及LineNumberInputStream都扩展自FilterInputStream——这个类是一个抽象的装饰类。而最高的抽象组件是InputStream类。

我们也可以以假乱真写一个输入流类

public class LowerCaseInputStream extends FilterInputStream { public LowerCaseInputStream(InputStream in) { super(in); } public int read() throws IOException { int c = super.read(); return (c == -1 ? c : Character.toLowerCase((char)c)); } public int read(byte[] b, int offset, int len) throws IOException { int result = super.read(b, offset, len); for (int i = offset; i < offset+result; i++) { b[i] = (byte)Character.toLowerCase((char)b[i]); } return result; } } public class InputTest { public static void main(String[] args) throws IOException { int c; try { InputStream in = new LowerCaseInputStream( new BufferedInputStream( new FileInputStream("test.txt"))); while((c = in.read()) >= 0) { System.out.print((char)c); } in.close(); } catch (IOException e) { e.printStackTrace(); } } }

6.装饰模式的一些缺陷:

产生各种小类,维护不便。有些代码会依赖特定的类型,而这样的代码一导入装饰者就出问题了。

 

示例代码下载

你可能感兴趣的:(设计模式,String,Class,扩展,byte,Blend)