1.这个模式可以称为“给爱用继承的人一个全新的设计眼界”的模式。牵扯到第五个设计原则:“类应该对扩展开放,而对修改封闭”。但是要注意,遵循这一标准会带来更多层次上的抽象,增加代码的复杂度,所以并不是所有类都要这样设计。
2.文中举了一个为辛巴克咖啡馆写一个计算咖啡价格+调料价格的类,使用了装饰模式——动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。我们就拿这个计算咖啡价格的东西举例子。
3.在原来的设计中,都是继承于Beverage这个超类中,多一项咖啡+调料组合就多一个子类,最后造成类的爆炸。而使用装饰模式,我们希望用装饰器(这里的调料)一层层的包含被装饰的咖啡,最后达到通过调用最外层的装饰者的cost()方法就可以委托其内部计算计算价钱。我们针对这个目标,从代表饮品的Beverage类下手,这是一个基类,代表一个逻辑上的抽象(但不一定要是抽象类,看是否有抽象方法来定),被装饰者和装饰者都使用该基类,在这个基类中定义了装饰者和被装饰者需要的方法,其中抽象方法是装饰者和被装饰者同时都需要的方法,而普通实现的方法则是装饰者覆盖使用的方法:
public abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription() {
return description;
}
publicabstractdouble cost();
}
我们将调料视为装饰器,这个装饰器超类为了能够将要被装饰的部分包起来,所以要继承自饮品这个超类:
public abstract class CondimentDecoratorextends 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.装饰模式的一些缺陷:
产生各种小类,维护不便。有些代码会依赖特定的类型,而这样的代码一导入装饰者就出问题了。
总结:
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案
FAQ:
为什么在一定要有Decorator这个类?
基于上边的这个例子我们可以看到Decorator这个类隔离了Component中可能出现的具体实现(比如上例中的getDescription方法),之所以要隔离室因为装饰者对这个方法的实现逻辑和高层的Component类实现的逻辑是不同的。在Decorator将一个方法退化为一个抽象方法,有助于督促具体的装饰器必须实现这个方法,而不会无意使用Component继承而来的方法(如果没有Decorator而直接继承自Component可能会因为实现逻辑不同而出现没有实现新逻辑而误用旧逻辑的情况,这会导致出现运行中错误,而退化为抽象方法后,具体装饰器则不得不实现这个方法,否则不可能编译通过,这就将错误压制在了编译阶段,显然,这相对于运行中出错是要好得多)。
分享到:
相关推荐
HeadFirst 设计模式学习笔记3--装饰模式 Demo http://blog.csdn.net/laszloyu/archive/2010/05/12/5582561.aspx
HeadFirst 设计模式学习笔记2--观察者模式 demo http://blog.csdn.net/laszloyu/archive/2010/05/12/5581769.aspx
http://blog.csdn.net/laszloyu/archive/2010/05/11/5579765.aspx 示例代码
HeadFirst设计模式学习笔记比较全面详细地讲解了13个设计模式,有利于大家更好的学习HeadFirst设计模式,希望亲们会喜欢~~~
Head First 设计模式学习笔记。更多内容请参见文章内容。
Head.First 设计模式学习笔记.pdf Head.First 设计模式学习笔记.pdf
著名的《Head First Design Pattern》学习笔记,摘要这本书中的设计思路。由于书本过长,整理出笔记帮助回想起设计模式。文件是docx格式,只能由OFFICE Word 2007之后的版本打开,内附Visio类图文件。本文由个人整理...
NULL 博文链接:https://chxiaowu.iteye.com/blog/1276845
设计模式Head First学习笔记,以及使用java编写的设计模式源码,Java原生sdk实现23种设计模式
学习设计模式时,做的笔记,主要参考了《Head First设计模式》
Head First学习笔记+Head First之装饰者模式高清PDF
最近在设计模式的一些内容,主要的参考书籍是《Head First 设计模式》,同时在学习过程中也查看了很多博客园中关于设计模式的一些文章的,在这里记录下我的一些学习笔记,一是为了帮助我更深入地理解设计模式,二...
近在学设计模式的一些内容,主要的参考书籍是《Head First 设计模式》,同时在学习过程中也查看了很多博客园中关于设计模式的一些文章的,在这里记录下我的一些学习笔记,一是为了帮助我更深入地理解设计模式,二...
VS2005 ASP.NET本地化学习笔记&感受 在自定义Server Control中捆绑JS文件 Step by Step 深度解析Asp.Net2.0中的Callback机制 使用 Web 标准生成 ASP.NET 2.0 Web 站点 ASP.NET 2.0基于SQLSERVER 2005的aspnetdb.mdf...
设计模式、设计模式 可复用面向对象软件的基础,实现了 Gof 的 23 种设计模式。 内容包括三大原则(继承、封装、多态)、类图、设计原则。 数据库 :floppy_disk: 参考 数据库系统原理。 参考 SQL 必知必会。 ...
学习笔记都在这里了 好好学习,天天向上!生命不息,阅读不止! 本仓库参考以下书籍或资料 JavaScript高级程序设计(第三版) You don't know JS 系列 ES6 标准入门 Node.JS深入浅出 图解HTTP HTTP权威指南 Head First...