GoF解释:
外观模式为子系统定义了一组统一的调用接口,这个接口会让子系统变得更加容易使用
为什么用这个设计模式:
当一个功能模块会调用多个子系统的时候应该怎么做?不用设计模式的情况下,我们需要持有或者访问这些子系统的实例对象或者单例对象,分别访问不同的系统,完成不同的功能。尤其是当一个功能需要调用不同的子系统的时候,代码操作会变得复杂。这违反了面向对象编程的一个特性:迪米特规则,程序解释是对于上层调用者而言,知道的细节越少越好。
模式说明:
隐藏功能调用所需要的子系统实现细节,提供一个简洁明了的接口供上层对象调用。上层对象只需要知道自己需要做什么,而不需要自己做的事需要哪些子系统一起去做和具体做的流程。
绝大多数游戏都会有一个中控总类去处理上层模块对系统的调用。
案例说明:角色花费金币升级
1.需求分析:客户端操作角色升级的时候有三个步骤,扣除金币,处理人物升级数据,升级之后触发解锁以及完成成就等。
2.传统实现流程:我们需要持有三个对象,货币系统,英雄系统,成就系统 去分别处理对应的逻辑,流程图如下:
当客户端在处理升级的时候,需要知道并持有所有参与的子系统,并且要知道具体的调用顺序。这样的代码不仅复杂,难于理解,因为根据迪米特原则,我只需要知道我执行升级就可以,而不必知道升级的具体细节是什么。并且代码不复用,维护也很麻烦,当升级的逻辑改变之后,我们又需要在每一个地方都做出相应的修改。
3.使用外观模式:定义一个外观类,持有 货币系统,英雄系统,成就系统 以及其他所有子系统。同步一个升级方法( levelUp ),上层模块只需要调用 levelUp 方法即可。改进的流程图如下:
这样不同的地方都调用外观类提供的LevelUp方法,模块只关心升级这个行为,不关心升级具体的实现逻辑。若升级逻辑又改变,统一修改外观类中的方法即可。
结论:外观模式是迪米特原则的精华实现,极大的符合了功能调用的极少知道原则。但是却破坏了面向对象的开闭原则,每次需要添加修改功能的时候我们都需要修改外观类。
外观模式虽然违反了开闭原则,但是几乎是所有游戏项目都会使用的一个设计模式,这个模式极大的精简了模块功能实现细节,也提供了各个系统之间通信的方式。当然我看到很多博客将各个系统之间的通信行为用中介者模式来解释,这样解释也是合理的,当然如果只看到这篇博客的读者,完全可以把这些都当成是外观模式。中介者模式的理解和应用可以翻阅博主的其他博客