1.装饰者模式:
· 动态的将责任附加到对象上。想要扩展功能,装饰者提供比继承更有弹性的替代方案。
2.遵循的原则:开放--关闭原则
类应该对扩展开放,对修改关闭
案例:
咖啡店为了应对扩张速度,准备制作订单系统,以满足饮料供应的需求。
1)原先的设计是这样色的:
购买咖啡时,可能会加入各种调料。如:蒸奶(Steamed Milk),豆浆(Soy),摩卡(Mocha)或者泡芙。
2)起初的设计方案是为每一种组合计算出自己的费用。穷举式的方式,会产生N多的类:
这种方式,估计没有人想接手后续的维护工作。
3)尝试从Beverage基类添加实例变量, 表示调料(牛奶,豆浆,摩卡,泡芙。。。。)
加入子类,每个类代表菜单中的一种饮料
这样做似乎解决了调料组合的问题。那么问题来了:
(1)调料的价格改变,需要更新现有代码
(2)一旦出现新的调料,父类需要加入新方法,改变父类cost()方法
(3)对新的饮料。例如:茶(tea),不需要牛奶,泡芙这些调料,但仍然会继承这些不符合的方法
(4)如果加双份摩卡怎么办?
我们的目标是允许类容易扩展,在不修改代码的情况下,可以搭配新的行为。 这样的设计具有弹性,可以应对改变,可以接受新的功能来应对改变的需求。
4)使用装饰者模式可以解决以上的问题。
采用组合的方式,以饮料为主体,运行时以调料来“装饰”饮料。
实现代码 如下:
饮料的抽象类
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";//浓咖啡
}
@Override
public double cost() {
return 1.99;
}
}
调料--摩卡
public class Mocha extends CondimentDecorator {
Beverage beverage;
public Mocha(Beverage beverage){
this.beverage=beverage;
}
public String getDescription() {
return beverage.getDescription() + ",Mocha";
}
/**
* 要计算摩卡饮料的价钱。首先把调用委托给被装饰对象,
* 以计算价钱,然后加上摩卡的价钱,得到最后的结果。
* @return
*/
@Override
public double cost() {
return 0.20 + beverage.cost();
}
}
调料--泡芙
public class Whip extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage ){
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ",Whip";
}
@Override
public double cost() {
return 0.10 + beverage.cost();
}
}
供应咖啡
public class Main {
public static void main(String args[]){
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" +beverage.cost());
Beverage beverage2 = new Espresso();
//双倍摩卡,牛奶咖啡
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription() + " $" +beverage2.cost());
}
}
打印结果:
装饰者模式的应用:Java I/O
写自己的IO装饰类只需要继承FilterInputStream类,重写read()方法。
在spring的命名体现:Spring 中用到的装饰者模式在类名上有两种表现: 一种是类名中含有 Wrapper
, 另一种是类名中含有Decorator
。 基本上都是动态地给一个对象添加一些额外的职责
例如:
Spring Session通过SessionRepositoryRequestWrapper继承ServletRequestWrapper,扩展了Request,并在SessionRepositoryFilter通过调用过滤链filterChain.doFilter(strategyRequest, strategyResponse);
将装饰的Request传入下一流程
装饰者模式的目的是,包装具有相同父类和接口的类.利用组合.然后重写相关的方法.