一、认识装饰者模式
定义:
装饰模式指的是在不必改变原类文件的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。提供了比继承更有弹性的替代方案。
作用:
在不用修改任何底层底层代码的情况下,给对象赋予新的功能。
本章可以称为“给爱用继承的人一个全新的设计眼界”
接下来,我们来看看下面这个例子!
二、咖啡店实例
以下是一家咖啡店最初的类设计。
四种具体的咖啡种类继承抽象类Beverage,并各自实现了其抽象方法cost()。

由于咖啡可以加入各种配料,
例如:蒸奶(Steamed Milk)、豆浆(Soy)、 摩卡(Mocha,也就是巧克力风味)或覆盖奶泡。
1)第一次糟糕的尝试如下...

他们将每种咖啡与各种配料的各种搭配都设计成了类!?

这样给维护带来了大麻烦!
如果某种饮料和配料价格变化,如果添加某种饮料或者配料,都需要更改许多个类的内容!
而且违反了多用组合,少用继承和针对接口编程,而不是针对实现编程这两个设计原则!
2)然后,有人提出用实例变量和继承追踪这些调理

代码如下
class Beverage{
String description;
public static float milkCost = .2f;
public static float soyCost = .1f;
public static float mochaCost = .3f;
public static float whipCost = .4f;
//各种调料的份数
int milk,soy,mocha,whip;
/*为调料设计set和get方法
....*/
boolean hasMilk(){return milk == 0?false:true;}
boolean hasSoy(){return milk == 0?false:true;}
boolean hasMocha(){return milk == 0?false:true;}
boolean hasWhip(){return milk == 0?false:true;}
public double cost() {
float condimentCost = 0.0f;
if (hasMilk()) { condimentCost += milkCost; }
if (hasSoy()) { condimentCost += soyCost; }
if (hasMocha()) { condimentCost += mochaCost; }
if (hasWhip()) { condimentCost += whipCost; }
return condimentCost;
}
如果想添加多份配料,也可以调整超类里的cost()方法。
public double cost(){
return milk*milkCost+soy*soyCost+mocha*mochaCost+whip*whipCost;
}
还是会存在下列问题
1.当调料价钱改变,我们要改变超类中各配料价格常量的值
2.当添加新调料,我们需要在超类中添加新的变量,需要改变超类中的cost()方法
3.而且,每一种饮料都会拥有每种调料的的实例变量,就会出现第一章中的问题。如果茶饮料里面加上摩卡就会很奇怪,尽管可以设置hasmocha() == false,但是从意义上讲还是很奇怪。
这里咱们要提出又一种设计原则
开放—关闭原则:类应该对扩展开放,对修改关闭。
这样的原则既有弹性可以应对变化,又保证了正确的代码的安全性。
我们的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配 新的行为。如能实现这样的目标,有什么好处呢?这样的设计具有弹性可以应对改变,可以接受新的功能来应对改变的需求。
3)用装饰者模式解决问题
通过上面两个例子,我们认识到一味继承不能解决所有问题。
这里要采用不一样的做法:我们要以饮料为主体,然后在运行时以调料来“装饰”(decorate)饮料。比方说,如果顾客想要摩卡 和奶泡深焙咖啡,那么,要做的是:
1拿一个深焙咖啡(DarkRoast)对象
2以摩卡(Mocha)对象装饰它
3 以奶泡(Whip)对象装饰它
4 调用cost()方法,将调料的价钱加上去。

通过上面的方法,我们了解到装饰者模式的一些特点
1.装饰者和被装饰对象有相同的超类型。
2. 你可以用一个或多个装饰者包装一个对象。
3.既然装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它。
4. 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
5.对象可以在任何时候被装饰,所以可以在运行时动态地,不限量地用你喜欢的装饰者来装饰对象。
下图为装饰者模式的模型图

运用到这家咖啡店就是下图

代码实现
public abstract class Beverage {
String description = "Unknown yet";
public String getDescription(){return description;}
public abstract double cost();
}
class DarkRoast extends Beverage {
public DarkRoast(){description = "DarkRoast";}
@Override
public double cost() {
return 1.2;
}
}
class HouseBlend extends Beverage{
public HouseBlend(){description = "House Blend Coffee";}
@Override
public double cost() {
return 1.4;
}
}
abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
class Soy extends CondimentDecorator{
Beverage beverage;
public Mocha(Beverage beverage){this.beverage = beverage;}
public String getDescription(){return beverage.getDescription()+",Soy";}
public double cost(){return 0.1+beverage.cost();}
}
class Mocha extends CondimentDecorator{
Beverage beverage;
public Mocha(Beverage beverage){this.beverage = beverage;}
public String getDescription(){return beverage.getDescription()+",mocha";}
public double cost(){return 0.3+beverage.cost();}
}
class Whip extends CondimentDecorator{
Beverage beverage;
public Whip(Beverage beverage){this.beverage = beverage;}
public String getDescription(){return beverage.getDescription()+",whip";}
public double cost(){return 0.4+beverage.cost();}
}
class Milk extends CondimentDecorator{
Beverage beverage;
public Milk(Beverage beverage){this.beverage = beverage;}
public String getDescription(){return beverage.getDescription()+",milk";}
public double cost(){return 0.2+beverage.cost();}
}
public class Main {
public static void main(String[] args) {
Beverage a = new DarkRoast();
a = new Milk(a);
a = new Milk(a);
a = new Mocha(a);
Beverage b = new HouseBlend();
b = new Milk(b);
b = new Mocha(b);
b = new Whip(b);
System.out.println(a.getDescription()+" "+a.cost()+"$");
System.out.println(b.getDescription()+" "+b.cost()+"$");
}
}
运行结果

java.io类

同理,输出流的设计也是雷同的。
学习装饰者模式可以帮我们更好地理解流相关的类。
网友评论