Cocos2d-x里面有一个非常明显的地方使用了外观模式,它就是SimpleAudioEngine。因为它为CocosDenshion这个子系统的一组接口提供了一个一致的界面,同时定义了一个高层接口,方便客户使用该子系统。
对于大多数用户来讲,游戏中操作声音,无非就是播放背景音乐和音效。CocosDenshion这个子系统封装了OpenAL,屏蔽了OpenAL操作声音的低级API。它提供了CDSoundEngine、CDAudioManager两个类来操作和管理声音。具体这两个类是如何工作的这里就不再讨论了,感兴趣的读者可以自行去研究相关代码。虽然CocosDenshion子系统已经封装了低级的操作声音的API,但是对于用户来讲,还是得了解该系统内部的类是如何一起协作来完成声音处理任务的。这样会加大用户使用此子系统的难度,同时,也使得客户程序与该子系统紧密耦合了。假如哪一天该子系统内部实现功能的组合有所变化,这势必会影响到客户程序。众所周知,操作游戏音乐的代码是分散在游戏代码各处的,那样会造成“散弹式”修改。这是个严重的代码坏味道,需要引起警觉,果断重构之!
而外观模式就可以完美地解决此问题,SimpleAudioEngine就是最好的例子。如果使用过SimpleAudioEngine的人会发现,它实在是太简单了。但是,SimpleAudioEngine并不是万能的,比如,它就无法实现循环播放音效的功能。但是,没有关系,你可以使用CDSoundEngine来实现这个功能。
请注意,SimpleAudioEngine并没有增加新的功能,而只是把子系统现有的类进行组合来完成一些常用的任务,简化客户程序的使用。子系统对于外观类是不知情的,即子系统不会包含外观类的指针。
优点:
1)它对客户屏蔽子系统组件,因而减少了客户处理的对象的数目,并使得子系统使用起来更加方便。
2)它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧密耦合的,这样当子系统功能组件发生变化的时候,只需要修改外观类的实现就可以了,避免了程序代码的“散弹式”修改。
3)同时,外观类并不限制客户直接使用子系统的功能组件,如果客户想使用子系统的更加高级的功能,可以越过外观类直接访问子系统的类。
缺点:
1)过多的或者不太合理的Façade也容易让人迷惑。到底是调用Façade好呢,还是直接调用子系统的模块好呢。
UML图:
定义:为子系统中的一组接口提供一个一致的界面,它定义了一个高层接口,这个接口使得子系统更加容易使用。它很好地体现了“最少知识原则”。
它的本质是:封装交互、简化调用。
实现(摘至维基百科):
考虑下面一个例子:
设计你(You)如何与一台计算机(facade)进行交互,而计算机是一个非常复杂的系统,它内部包含CPU、HardDrive等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
|
游戏开发过程中,暂时还没发现此模式的明显用法。不过,模式不是说学习了一定要马上就用到,那样会导致过度设计。如果读者开发游戏过程中,积累出一套比较成熟的框架,而这个框架又可以划分多个子系统,比如碰撞子系统、网络子系统、数据持久化子系统等。当外部使用此子系统时,操作的类过多,理解起来特别复杂时,这时候就可以考虑引入一个Façade类,来简化客户程序与子系统之间的调用关系。
通常来讲只需要一个外观类,所以可以采用单例模式。