@zongwu
2017-02-05T09:34:39.000000Z
字数 4048
阅读 339
动态的给一个对象添加一些额外的职责。
现在是2187年,智能机器人已经发展到可以一个新的里程碑高度。全球知名厂商华为正在推广新一代“女友机器人”,该型号机器人除了不能生孩子其它都可以做。
今天顾客Alice 进入你的旗舰店正准备挑选她的下一任“机器人女友”。Alice希望她拥有 “大胸”、“肤白”、“瓜子脸”、“大眼睛”……(省略300个要求)。
好吧,Alice并不算本店遇到的最挑剔的客户,但幸好我们支持Alice作出他心爱的选择。因为我们有多于3000个可选方案,可供用户挑选自由组合。
最后Alice选择了,“C罩杯”、“瓜子脸”、“丰满”、“翘臀”套餐,确定付款之后。后台的3D打印机正在迅速的制造中,经历10分钟的漫长等待。Alice取到了他满意的机器人女友。
客户端(Alice)
为 被装饰的对象(机器人)
添加了许多 装饰对象(肤色、胸型、脸型、身型)
。
现在分析得到了下面的类图,我们似乎找到了解决的方案,但是总还觉得差点什么?
我们进入商店并挑选了机器人的芯片、材质等,并确认下单。好吧,现在我们拥有了机器人未加任何装饰的原始对象,现在思考如何为它添加装饰。
一番思索后工程师Bob提出了方案1 :
public class Customer {
public static void main(String[] args) {
Machine machine = new Machine();
machine.add(new Body("纤细"));
machine.add(new Chest("C罩杯"));
machine.add(new Butt("翘臀"));
machine.add(new Face("瓜子脸"));
}
}
public class Machine {
public void add(Body value) {
System.out.println(value);
}
public void add(Chest value) {
System.out.println(value);
}
public void add(Butt value) {
System.out.println(value);
}
public void add(Face value) {
System.out.println(value);
}
}
// 此处示意下举出一个装饰对象,其他对象与其结构一致
public class Body {
public String value;
public Body(String value) {
this.value = value;
}
@Override
public String toString() {
return "身型{" +
"value='" + value + '\'' +
'}';
}
}
运行结果:
身型{value='纤细'}
胸型{value='C罩杯'}
臀型{value='翘臀'}
脸型{value='瓜子脸'}
Bob在思索后立即去实施,并发现了方案1的一处致命问题 —— 每添加一个装饰,就要修改机器人的源代码程序,去匹配添加的装饰
。
于是Bob在思索后考虑是否可以不改变机器人的源代码程序,动态的在外部修改其外观
。
于是出现了方案2:
public class Customer {
public static void main(String[] args) {
// 先配置容器
MachineContainer container = new MachineContainer();
container.add(new Body("纤细"));
container.add(new Chest("C罩杯"));
container.add(new Butt("翘臀"));
container.add(new Face("瓜子脸"));
// 再用容器去配置机器人
Machine machine = new Machine();
machine.add(container);
}
}
public class Machine {
public void add(MachineContainer container) {
System.out.println("TODO:解析容器并为Machine添加职责");
}
}
public class MachineContainer {
public void add(Body value) {
System.out.println(value);
}
public void add(Chest value) {
System.out.println(value);
}
public void add(Butt value) {
System.out.println(value);
}
public void add(Face value) {
System.out.println(value);
}
}
这样一来Bob觉得 机器人
添加 装饰容器
的逻辑几乎不会发生变化,而容器又可以单独隔离出来配置不会影响机器人本身。
但转念一想,不对啊。这类虽然是隔离出来了,可是还是没有解决每添加一个装饰对象,就要修改一下容器的悲惨现实!!!
于是Bob想啊想,觉得虽然每次都添加了新的装饰组件,但是装饰组件的行为并没有太大的改变,是否可以抽象出来。
// 抽象出接口 表示类型是装饰组件类型
public interface IDecorComponent {
}
// 修改容器代码 —— 去掉了对具体类型的耦合
public class MachineContainer implements IDecorComponent {
public void add(IDecorComponent component) {
System.out.println("添加了" + component);
}
}
// 装饰物实现了无方法的接口
public class Body implements IDecorComponent {
public String value;
public Body(String value) {
this.value = value;
}
@Override
public String toString() {
return "身型{" +
"value='" + value + '\'' +
'}';
}
}
Bob编译执行看了下结果,发现自己还遗漏了一个TODO
还未做。
添加了身型{value='纤细'}
添加了胸型{value='C罩杯'}
添加了臀型{value='翘臀'}
添加了脸型{value='瓜子脸'}
TODO:解析容器并为Machine添加职责
机器人组装完成
于是继续想啊想,他意识到无论是委托给 装饰容器
还是机器人
本身都避免不了要为机器人
添加装饰物
这事。既然在劫难逃,那就只能勇敢面对了。最终的方案:
public class Customer {
public static void main(String[] args) {
Machine machine = new Machine();
// 配置装饰容器
IDecorComponent component = new MachineContainer(machine);
component = new Body(component, "纤细");
component = new Butt(component, "翘臀");
component = new Chest(component, "C罩杯");
component = new Face(component, "瓜子脸");
// 触发添加行为
component.addBehiavor();
}
}
public interface IDecorComponent {
void addBehiavor();
}
public class Machine {
// 对Machine 没有任何侵入
}
public class MachineContainer implements IDecorComponent {
private Machine machine;
public MachineContainer(Machine machine) {
this.machine = machine;
}
public void add(IDecorComponent component) {
System.out.println("添加了" + component);
}
@Override
public void addBehiavor() {
System.out.println("===触发了装饰物的行为===");
}
}
// 新增的类,用于委托递归操作
public class Decor implements IDecorComponent {
IDecorComponent component;
public Decor(IDecorComponent component) {
this.component = component;
}
@Override
public void addBehiavor() {
// 委托装饰的组件继续执行相关的行为
this.component.addBehiavor();
}
}
public class Body extends Decor {
public String value;
public Body(IDecorComponent component, String value) {
super(component);
this.value = value;
}
@Override
public String toString() {
return "身型{" +
"value='" + value + '\'' +
'}';
}
@Override
public void addBehiavor() {
// 触发了递归操作
super.addBehiavor();
System.out.println("添加了" + toString());
}
}
运行结果如下:
===触发了装饰物的行为===
添加了身型{value='纤细'}
添加了臀型{value='翘臀'}
添加了胸型{value='C罩杯'}
添加了脸型{value='瓜子脸'}