外观模式(封装交互,简化调用)
2017-02-21 本文已影响12人
幺鹿
前言
机器人Samu
与主人Alice
的故事仍在继续,这次Samu
宕机了。Alice
重启了Samu
,Samu
在每次重启的时候都会做些预定的事件。
比如:
- 初始化多种音乐类型的曲库
- 跳舞(肚皮舞)
- 唱歌(千里之外)
- 做菜(红烧肉)
正文
现在需要实现初始化
这个功能,这个功能包含的子功能已经在上面陈列出来了。
场景分析:
- 我们把“人与机器人”称作“人机交互的上下文”。
HumanComputerInteraction.Context
- 我们把 “人与机器人对话的过程” 称作一次“人机交互”。
HumanComputerInteraction
代码实现
先看下面两段代码片段,没有任何接口、继承等。我想说设计模式应着重理解其思想,而非特定模式下的结构实现
。
public class Client {
public static void main(String[] args) {
// 创建交互的上下文对象 —— 即"谁与机器人在交互"。
HumanComputerInteraction.Context context = new HumanComputerInteraction.Context(new Machine("Samu"), new User("Alice"));
// 创建人机交互对象
HumanComputerInteraction interaction = new HumanComputerInteraction(context);
// 初始化人机交互
interaction.setUp();
}
}
public class HumanComputerInteraction {
private Context context;
public HumanComputerInteraction(HumanComputerInteraction.Context context) {
this.context = context;
}
public void setUp() {
// 初始化曲库
final Machine machine = context.getMachine();
final MusicDatabase database = machine.getDatabase();
database.initDatabase();
// 初始化命令
final Invoker invoker = context.getInvoker();
invoker.invoke(new CommandAdapter(CookCommandImpl.KEY_COOK, "红烧肉", context));
invoker.invoke(new CommandAdapter(DanceCommandImpl.KEY_DANCE, "肚皮舞", context));
invoker.invoke(new CommandAdapter(SongCommandImpl.KEY_SONG, "千里之外", context));
}
}
setUp
方法中封装了,初始化曲库、唱歌、跳舞、做菜等一系列事项。其也体现了外观模式(也称作 门面模式)
的本质:封装交互,简化调用
。
总结
外观模式本质.png外观模式的本质:封装交互,简化调用。
如上图,蓝色背景其实可以视作一个子系统,由外观类组合拼装各个功能块。如果需要暴露子系统的功能,则会考虑暴露子系统的接口。这意味着在一个良好设计的系统中,子系统仅暴露它应该暴露的接口。因为子系统并不知道,调用它的是外观类还是客户端类。
引入外观类是为了解耦与子系统的关联,但并不限制客户端直接调用子系统。
不建议在外观类中增加子系统的功能,因为这并不符合外观模式封装交互,简化调用
的本质。建议直接扩展子系统的功能。
当子系统功能发生改变时,可能需要修改外观类以适应子系统功能的变化,导致外观模式
不符合开闭原则
。你可以通过抽象外观类,一定程度上缓解该问题。