《head first 设计模式》day three 装饰者模式

今天有时间看了head first设计模式的第三个模式--装饰者模式  Decorate Model

文章一开头就着重强调一个开发原则--对修改关闭,对扩展开放的开闭原则

装饰者模式定义--动态的将责任附加到对象上。想要扩展对象,装饰者提供了有别于继承的另一种方式。

装饰者解决的问题如下:星巴zi里面有很多款饮料,星冰乐,卡布奇诺,美式咖啡等。但是统一都是饮料(Beverage)

在基本咖啡的基础上我们可以添加牛奶成为卡布奇诺,加巧克力成为摩卡,加冰加水成为美式冰咖啡,这些普通的饮料可以继承Beverage,而且他们都有一个属性是价格.我们结账的时候可以获取这个属性,但是问题来了,如果我们想要一个double摩卡这个时候怎么计算价格。Beverage.cost+Mocha.cost+Mocha.cost?.那如果我们想要double摩卡里面加奶。计算方法就要换为Beverage.cost+Mocha.cost+Mocha.cost+Milk.cost;如此类推下去我们发现问题会比较复杂,我们真的要修改价格计算方法?亦或是创建另外的一个类专门处理价格计算,名字叫价格计算类?这个时候我们是不是就又落入面向实现编程了??(仔细一想之前编程中确实有很多这样的情况,喜欢直接修改方法,或者创建一个帮助类),但是这样真的可以做到良好的扩展么!再仔细想想我们开头讲到的开闭原则。这个时候装饰者模式就有了用武之地,书中的例子:

1:以饮料为基本类  Beverage,创建一个子类  深度烘培----DarkRoast

2:如果我们想要加巧克力 那么以 Mocha 对象装饰 DarkRoast。

3:如果我们想要加奶泡 以Whip对象装饰它

4:调用cost方法,利用(delegate)委托,把所有的价格求和

类UML图入下(算了,其实我不想画图)

画图时间长,结果用power designer画出来的图像很丑,继承竟然是依赖的虚线。简直就是扯淡。我直接写代码好了

public class Beverage{//饮料父类
String getDescription(){
 return "基本coffe";
}
double cost(
 return 10.0;
)
}

public class DarkRoast extends Beverage{//基本的子类
String getDecription(){
return "深度烘焙";
}

 double cost(){
 return 5;
}
}
public class Decorate extends Beverage{//装饰父类

String getDescription(){
return "装饰者";
}
}
public class Mocha extends Decorate{
Beverage derecate;
double cost(){
return 5+ derecate.cost();
}
String getDecription(){
return "摩卡";
}
}
这样的时候,我们就可以看出,Mocha其实是间接的继承了Beverage,摩卡的本质没有变,他是饮料,但是是加了巧克力的咖啡饮料。而且作为装饰者,Mocha同样可以在运行时改变,我们可以用它动态的替代卡布奇诺,或者是星冰乐。这就是装饰者的魅力,

现实中我们使用装饰者模式的地方是:java.io;;

很多人应该跟我一样,对java的IO表示头大,java.io的类实在是太多了,一个输入流就可以有InputStream FileInputStream ,BufferedInputStream,LineNumberInputStream 多个类,但其实BufferedInputStream和LineNumberInputStream 都是FileInputStream 的包装类,他们只是在自己的类中添加了一个附加的责任,实现缓冲加载或者是行数据加载。

同样输出流也是。使用了很多包装类,每个包装类里面实现了一点点的附加功能,让我们在使用的时候更简单,不用自己自制轮子。但是也同时暴露了装饰者模式的一个弊端,子类繁多,有时候我们也会糊涂在使用的时候到底需要使用哪一个类。


上面就是java.IO的装饰者模式的类uml图。

猜你喜欢

转载自blog.csdn.net/David_lou/article/details/79210246