Cocosd-x設計模式之四 :外觀模式

   這一篇將來學習“外觀模式”,在cocos2d-x引擎中,一個採用此設計模式的經典類就是SimpleAudioEngine,此模式的核心思想是,爲子系統中的一組接口提供一個一致的界面,它定義了一個高層接口,這個接口使得上層使用子系統更加容易,同時,它實現了子系統與上層之間的鬆耦合關係,而子系統內部的功能組件往往是緊密耦合的,這樣當子系統功能組件發生變化的時候,只需要修改外觀類的實現就可以了,避免了程序代碼的“散彈式”修改。


1.應用場景

Cocos2d-x裏面有一個非常明顯的地方使用了外觀模式,它就是SimpleAudioEngine。因爲它爲CocosDenshion這個子系統的一組接口提供了一個一致的界面,同時定義了一個高層接口,方便客戶使用該子系統。

對於大多數用戶來講,遊戲中操作聲音,無非就是播放背景音樂和音效。CocosDenshion這個子系統封裝了OpenAL,屏蔽了OpenAL操作聲音的低級API。它提供了CDSoundEngine、CDAudioManager兩個類來操作和管理聲音。具體這兩個類是如何工作的這裏就不再討論了,感興趣的讀者可以自行去研究相關代碼。雖然CocosDenshion子系統已經封裝了低級的操作聲音的API,但是對於用戶來講,還是得了解該系統內部的類是如何一起協作來完成聲音處理任務的。這樣會加大用戶使用此子系統的難度,同時,也使得客戶程序與該子系統緊密耦合了。假如哪一天該子系統內部實現功能的組合有所變化,這勢必會影響到客戶程序。衆所周知,操作遊戲音樂的代碼是分散在遊戲代碼各處的,那樣會造成“散彈式”修改。這是個嚴重的代碼壞味道,需要引起警覺,果斷重構之!

而外觀模式就可以完美地解決此問題,SimpleAudioEngine就是最好的例子。如果使用過SimpleAudioEngine的人會發現,它實在是太簡單了。但是,SimpleAudioEngine並不是萬能的,比如,它就無法實現循環播放音效的功能。但是,沒有關係,你可以使用CDSoundEngine來實現這個功能。

請注意,SimpleAudioEngine並沒有增加新的功能,而只是把子系統現有的類進行組合來完成一些常用的任務,簡化客戶程序的使用。子系統對於外觀類是不知情的,即子系統不會包含外觀類的指針。

2.使用外觀模式的優缺點

優點:

1)它對客戶屏蔽子系統組件,因而減少了客戶處理的對象的數目,並使得子系統使用起來更加方便。

2)它實現了子系統與客戶之間的鬆耦合關係,而子系統內部的功能組件往往是緊密耦合的,這樣當子系統功能組件發生變化的時候,只需要修改外觀類的實現就可以了,避免了程序代碼的“散彈式”修改。

3)同時,外觀類並不限制客戶直接使用子系統的功能組件,如果客戶想使用子系統的更加高級的功能,可以越過外觀類直接訪問子系統的類。

缺點:

1)過多的或者不太合理的Faade也容易讓人迷惑。到底是調用Faade好呢,還是直接調用子系統的模塊好呢。

3.外觀模式的定義及一般實現

UML圖:

FacadeDesignPattern.png

定義: 爲子系統中的一組接口提供一個一致的界面,它定義了一個高層接口,這個接口使得子系統更加容易使用。它很好地體現了“最少知識原則”。

它的本質是:封裝交互、簡化調用。

實現(摘至維基百科):

考慮下面一個例子:

設計你(You)如何與一臺計算機(facade)進行交互,而計算機是一個非常複雜的系統,它內部包含CPU、HardDrive等。

/* Complex parts */
class CPU {
    public void freeze() { ... }
    public void jump(long position) { ... }
    public void execute() { ... }
}
class Memory {
    public void load(long position, byte[] data) { ... }
}
class HardDrive {
    public byte[] read(long lba, int size) { ... }
}
/* Facade */
class Computer {
    private CPU cpu;
    private Memory memory;
    private HardDrive hardDrive;
    public Computer() {
        this.cpu = new CPU();
        this.memory = new Memory();
        this.hardDrive = new HardDrive();
    }
    public void startComputer() {
        cpu.freeze();
        memory.load(BOOT_ADDRESS, hardDrive.read(BOOT_SECTOR, SECTOR_SIZE));
        cpu.jump(BOOT_ADDRESS);
        cpu.execute();
    }
}
/* Client */
class You {
    public static void main(String[] args) {
        Computer facade = new Computer();
        facade.startComputer();
    }
}

4.遊戲開發中如何運用此模式

遊戲開發過程中,暫時還沒發現此模式的明顯用法。不過,模式不是說學習了一定要馬上就用到,那樣會導致過度設計。如果讀者開發遊戲過程中,積累出一套比較成熟的框架,而這個框架又可以劃分多個子系統,比如碰撞子系統、網絡子系統、數據持久化子系統等。當外部使用此子系統時,操作的類過多,理解起來特別複雜時,這時候就可以考慮引入一個Faade類,來簡化客戶程序與子系統之間的調用關係。

5.外觀模式與其它模式的關係

通常來講只需要一個外觀類,所以可以採用單例模式。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章