首先看一个具体例子
代码类之间的关系如下:
解释:第一部分,是父类,之所以要这个父类是因为Mocha或者soy内部持有一个父类的引用,只有持有这个引用,才可以既覆盖父类(通过继承)的方法又装饰父类(通过调用父类的引用的相同的方法(不同的方法也可以调))的方法。第二部分,就是已经实现了父类大部分方法的子类,也就是被装饰的类(通过Mocha和Soy来增强)。第三部分,一个装饰器,用来表述哪些方法需要子类去实现(抽象类)。第四部分,装饰第二部分的类,可以在第二部分类的基础上,进行二次开发。
接下来看下官方的类图:
官方装饰模式类图
可以看出,和我们的例子差不多。
废话不多说,直接上代码。
Beverage:
public abstract class Beverage {
protected String description = "Unknown Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
DarkRoast:
public class DarkRoast extends Beverage {
public DarkRoast() {
description = "DarkRoast";
}
public double cost() {
return .99;
}
}
CondimentDecorator:
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
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();
}
}
Whip:
public class Whip extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
public double cost() {
return .10 + beverage.cost();
}
}
main主函数:
Beverage beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
//这里传入的beverage2不是Beverage beverage2 = new DarkRoast();而是经过修饰后的 beverage2 = new Mocha(beverage2);每次传入的都是经过修饰后的
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
输出结果:
DarkRoast, Mocha, Mocha, Whip $1.49
运行过程如下图所示:
运行过程1
下面解释下:第一次new DarkRoast();的时候beverage2指向堆中的DarkRoast;
第二次beverage2 = new Mocha(beverage2)(第一个Mocha中有个成员变量Beverage beverage;),Mocha中的成员变量beverage指向了之前的beverage2,由于beverage2指向DarkRoast,也就是说Mocha中的成员变量beverage也指向DarkRoast。
再次,beverage2 = new Mocha(beverage2),第二个Mocha中的成员变量beverage也指向之前的beverage2 ,由于beverage2 还是指向第一个Mocha,所以第二个Mocha中的beverage也指向第一个Mocha,这里之所以都可以指向Mocha或者beverage2是因为他们发父类型是一样的。
最后,beverage2 = new Whip(beverage2);原理也是一样。其实,这里的beverage2只是用来接收不同的对象,保持一个引用。也可以每次都使用一个新的Beverage beverageNew来接收,这样的话,每次传入的就是这个新的beverageNew。使用每次new一个新对象的流程图如下:
运行过程2
打印结果也是一样。
当然,也可以这样写代码:
Beverage beverage2 = new DarkRoast();
beverage2 = new Whip(new Mocha(new Mocha(beverage2)));
System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
这样写的代码的流程图其实就是少了两条指向new出来的Mocha对象的虚线。
好了,java装饰模式到此讲完了。下一篇继续模式之路。。。喜欢请关注作者。谢谢。