一:装饰者模式
想要学会装饰者模式必须理解装饰者模式的作用和所依赖的原则。
理解了作用可以帮助我们在以后的开发中怎么应用装饰者模式,理解了原则可以帮助我们怎么去书写装饰者模式。
二:装饰者模式的作用:
官方作用说明:动态地将责任附加到装饰者对象上。
自己的理解:对某一类对象的功能的扩展,就可以使用装饰的模式。
三:装饰者模式依赖的原则:
1:开放--关闭原则:
对类的功能扩展开放,对类的源码的修改进行关闭。
2:开放--关闭原则的详解:
我们可以对已有的类添加功能,但不能对已有的类进行修改操作(所谓的修改就是增删改),意思别人写好的代码我们不 能对他进行修改。那么问题来了我们不能修改别人的代码,如何扩展类的功能呢?请看下面代码的分析,你就能看懂装饰者模式是如何不改源码就能扩展类的功能。
四:源码分析
现在我们假设在很久以前有一个程序员写了一个Beverage(饮料)抽象类和继承了Beverage的具体类EspressoCoffe(浓咖啡),用description属性描述饮料,用cost方法计算咖啡的价格代码如下 :
package decrationModel;
|
package decrationModel;
public EspressoCoffe() {
|
现在的需求是:又来了一个程序员他想往EspressoCoffe(浓咖啡)里添加摩卡,现在看看装饰者模式是怎么往浓咖啡里添加摩卡的且不修改源码。
在看装饰者模式之前的先明白两个定义:一个是装饰者,一个是被装饰者。
现在我们是在往浓咖啡(EspressoCoffe)里添加摩卡(Mocha),这就是在用摩卡装饰浓咖啡。
所以浓咖啡(EspressoCoffe)是被装饰者,摩卡(Mocha)是装饰者。
在摩卡(Mocha)类里声明了一个饮料(beverage)属性,用来接收被装饰者。
package decrationModel; *所有装饰器都必须继承此类 * /* } |
package decrationModel; @Override } |
public static void main(String[] args) { //1现在顾客点了一杯浓咖啡 EspressoCoffe coffe=new EspressoCoffe(); //2:顾客现在又要求在浓咖啡里添加点摩卡 Mocha mocha=new Mocha(coffe); //3:现在顾客感觉添加摩卡的咖啡不错,他想看看这杯添加摩卡浓咖啡的介绍 String description = mocha.getDescription(); System.out.println("介绍:"+description); //4顾客喝完咖啡就需要结账了 double cost = mocha.cost(); System.out.println("费用:"+cost); } |
现在我们来看看所谓的功能扩展是怎么扩展的:
功能的扩展其实就是将装饰者的功能与被装饰者的功能进行组合。
而我们也对两个功能进行了组合:在装饰者getDescription()与cost()方法。
现在我们又来解释一下官方的定义:动态地将责任附加到装饰者对象上。
如果顾客只要浓咖啡而不要摩卡或者其他调料装饰,那么获取咖啡的描述和价格都需要用咖啡对象去调用。
如果顾客要求用摩卡或者其他调料装饰,那么获取浓咖啡价格和描述我们就不要用浓咖啡对象去调用了,而是交给摩卡对象去调用。这样我们获取到的是总价格和总描述。所以获取价格和描述的责任我们也动态的附加到摩卡装饰者对象上面去了。
最后一个问题:为什要让装饰者与被装饰者具有共同的祖先(例如浓咖啡和摩卡就具有共同的祖先)
这么做的目的是为了继承类型,而不是继承行为。因为摩卡装饰浓咖啡之后他还是一杯饮料。代码里面我们也确实没有继承行为,我们都是重新写了子类的行为。
设计初衷:通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,(记住是生成很多的子类),增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的。
要点: 装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为
提示:io流使用的就是装饰者模式