Decorator译为装饰,生活中有很多装饰器模式的例子。比如你去买手抓饼,可以加料,当然最重要的是它是手抓饼。老板不可能把所有类型的手抓饼都做好,而是根据你的需要,比如你要加培根和鸡蛋,再加肉松,老板则煎好饼,再把料放好,把料放进饼里就是对饼的一种“装饰”。当然,你也可以把装好的手抓饼让老板再加点其他的料(当然现实中不会这样)。
所谓装饰器模式,即将被装饰对象,对应上面例子的饼,用其他的料给它 “装饰” 让它不仅仅是饼,而是具有了相比于被装饰对象更多的功能。
下面就以上面的手抓饼为例,具体看看装饰器模式。
涉及的类
AddMaterial | 用于做出手抓饼的抽象类 |
Cake | 饼,被修饰对象 |
Materials | 料的抽象类 |
Baken | 给饼加培根 |
Egg | 给饼加鸡蛋 |
类图
Cake类
Cake类即代表饼类,为 被装饰的类,该类继承了AddMaterial(抽象类)类,该类在下面介绍。在Cake类中重写了抽象父类的getCake方法,返回 “饼” 字符串。
public class Cake extends AddMaterial{
@Override
String getCake() {
return "饼";
}
}
AddMaterial类
该类为抽象类(也可以设计为接口),是为了 统一被装饰的类与装饰类,使得 被装饰的类的对象实例被装饰类装饰后仍然能够保持接口(API)的透明性(可参考结城浩《图解设计模式》)。该类声明了一个抽象方法 getCake ,供子类去重写其中的逻辑。
abstract class AddMaterial {
abstract String getCake();
}
Materials类
在AddMaterial 类之下,并不是直接由具体的材料类继承,而是先抽象出一个材料类,在本类中聚合其父类AddMaterial,并在本类构造器初始化AddMaterial的子类,这样子具体的子类可以继承该属性,并可以调用该子类的方法。
abstract class Materials extends AddMaterial{
protected AddMaterial addMaterial;
public Materials(AddMaterial addMaterial) {
this.addMaterial = addMaterial;
}
}
Egg类
Egg类是Materials类的具体实现子类,重写了getCake方法,并使用了Materials类聚合的AddMaterial。在Egg类中,getCake方法调用了addMaterial类的getCake方法,可能是调用 被装饰的类Cake,也可能是来自一个装饰类(装饰了被装饰类)。
public class Egg extends Materials{
public Egg(AddMaterial addMaterial) {
super(addMaterial);
}
@Override
String getCake() {
return addMaterial.getCake() + "-" + "鸡蛋";
}
}
Baken类
Baken类也是Materials类的具体实现类,和上面Egg类相同。
public class Baken extends Materials{
public Baken(AddMaterial addMaterial) {
super(addMaterial);
}
@Override
String getCake() {
return addMaterial.getCake() + "-" + "培根";
}
}
Main类
Main类中,创建了基本的 被装饰的对象 Cake,再创建了Baken并将Cake放入,这就是将cake使用培根 装饰 cake,接着将被培根装饰的cake再放入Egg类的构造器中,得到由Egg和Baken装饰的cake。
public class Main{
public static void main(String[] args) {
AddMaterial cake = new Cake();
AddMaterial bakenAndCake = new Baken(cake);
AddMaterial eggAndCakeAndBaken = new Egg(bakenAndCake);
AddMaterial eggAndCake = new Egg(cake);
System.out.println(eggAndCakeAndBaken.getCake());
System.out.println(eggAndCake.getCake());
}
}
输出结果:
饼-培根-鸡蛋
饼-鸡蛋
学习结城浩《图解设计模式》记