遊戲程式設計模式 子類沙盒

2022-08-24 10:00:10 字數 3268 閱讀 7532

「使用基類提供的操作集合來定義子類中的行為。「

遊戲引擎的每個部分都將與這些類產生耦合;

當這些外部系統需要改變時,superpower類的**很可能遭到隨機性的破壞。因為我們的superpower類與外部**存在很強的耦合關係或者說依賴關係,一旦外部系統發生改變,不可避免的會影響到superpower類;

定義所有superpower都遵循的不變數時很困難的。例如說我們像保證所有的power類的音效都能得到合理的優先順序劃分和排隊,如果這些派生類都直接呼叫音效引擎的話,這將很難實現。

這個時候我們應該怎麼辦了?

這個時候衍生了乙個新的問題,如何安放這些方法了?

也就是說子類應該如何來組織使用這些方法實現功能了?為此我們定義乙個沙盒方法,這個時候子類必須實現的抽象保護方法。所以接下來你要做的就是:

建立乙個類繼承基類;

重寫沙盒函式activate();

通過呼叫基類提供的方法來實現子類的功能;

也就是我們把基礎的操作**提取到更高的層次來解決冗餘的問題。一旦我們在子類中發現大量的重複**,我們就會把它上移到基類中作為乙個新的基本方法。也就是說我們把子類的耦合都提取到父類中,這樣耦合的地方就只有一處,每個子類僅與基類耦合。一旦遊戲的某個部分發生變化時,我們只需要修改基類即可,不會牽扯到子類的修改。這樣的設計會催生一種扁平的類層次架構。你的繼承鏈不會太深,但會有大量的子類,這些子類與基類掛鉤。通過乙個類派生大量的子類,我們限制了該**在**庫中的影響範圍。

乙個基類定義乙個抽象的沙盒方法和一些預定義的操作集合。通過將它們設定為受保護的狀態以確保它們僅供子類使用。每個派生出的沙盒子類根據父類提供的操作來實現沙盒函式。

沙盒模式是運用在多數**庫里、甚至遊戲之外的一種非常簡單通用的模式。如果你正在部署乙個非虛的受保護方法,那麼你很可能正在使用與之類似的模式。沙盒模式適用於一下情況:

這些年「繼承」一詞被部分程式圈所詬病,原因之一使基類會衍生越來越多的**。這個模式尤其受這個因素影響。

由於子類使通過它們的基類來完成各自功能的,因此基類最終會與那些需要與其子類互動的任何系統產生耦合。當然,這些子類也與它們的基類密切相關。這個蜘蛛網式的耦合使得無損的改變基類使很困難的——你遇到類脆弱的基類問題。但從另乙個角度來說,你的所有耦合都被聚集到了基類,子類現在與其它部分劃清了界限。理想的情況下,你的絕大部分操作都在子類中。這樣意味著你的大量**庫使獨立的,並且更容易維護。

如果你仍然發現本模式正在把你的基類變得龐大不堪,那麼請考慮一些提供的操作提取到乙個基類能管理的獨立類中。這裡可以借鑑元件模式。

示例superpower基類:

class superpower

protected

:

virtual

void activate() = 0

;

void move(double x, double y, double

z)

void

playsound(soundid sound)

//other methods....

};

這裡activate就是沙盒函式。由於它是抽象虛函式,因此子類必須要重寫它。這是為了讓子類實現者能夠明確它們該對子類做什麼。接下來讓我們實現一些子類來說明子類是如何建立的。

class skylaunch:public

superpower

};

沙盒模式就是如此的簡單,**並不太多,它描述的是乙個基本的思想,但並沒有給出過於詳細的機制。所以這裡你還是要面臨一些抉擇:

這裡有兩個極端,一種是基類什麼操作都不提供,只提供乙個沙盒方法;而另乙個就是基類提供子類所有需要的操作。子類僅與基類耦合,不同呼叫任何外部系統。前者基類不提供任何操作,所以基類與外部系統的耦合度低,隨著基類提供的操作多,與外部系統的耦合就越來越高。如果我們把所有的操作都聚集到基類,那麼基類就會變得很大,維護起來也就會越來越困難,所以我們應該如何做出選擇了?

這個設計模式的挑戰在於最終你的基類可能塞滿了方法。你能夠通過轉移一些函式到其它類中來緩解這種情況,並於基類的相關操作中返回相應的類物件即可。就像這樣:

class

soundplayer

private

: soundplayer soundplayer_;

};

把提供的操作分流到乙個像這樣的輔助類中能給你帶來些好處。

你的基類通常希望封裝一些資料以對子類保持隱藏。比如,我們想在系統中新增一些例子特效,那我們如何把粒子系統物件傳遞給基類了?

像這樣:

class

superpower

private

: particlesystem*particles_;

};

這樣雖然解決了問題,但同時帶來了另乙個問題。就是每個繼承類都需要乙個建構函式來呼叫基類的建構函式並傳遞那個粒子系統引數。這樣就向每個子類暴露了一些我們並不希望暴露的狀態。而且,這樣也存在維護負擔。如果後面我們新增另乙個狀態,那麼我們不得不修改每個繼承類的建構函式來傳遞它。

為了避免通過建構函式傳遞所有的東西,我們可以把初始化拆分為兩個步驟。建構函式不帶引數僅僅負責創造物件,然後我們通過乙個直接定義在基類中的函式來傳遞它所需要的其它資料。比如像這樣:

superpower* power = new

skylaunch();

power->init(particles);

這裡可能發生的就是我們忘記呼叫init函式,那樣我們就只能得到構造了一半的物件。對於這個問題可以通過封裝乙個方法來解決。

superpower* createskylaunch(particlesystem *particles)

如果你想控制只能使用這個函式來建立skylaunch物件,可把skylaunch的建構函式宣告為私有的來實現,類似單例模式的實現方式。

我們可以把我們不想暴露的狀態宣告為基類的私有成員,同時也是靜態的,遊戲將不得不保證初始化這個狀態,但它僅需要整個遊戲初始化一次,只要保證盡早呼叫初始化函式即可。這中做法還帶來乙個好處就是因為是靜態變數,所有例項共用乙個,所以占用的記憶體更少。

前面的方法嚴格要求外部**必須在基類使用相關狀態之前將這些狀態傳遞給基類,這給周圍的**的初始化工作帶來了負擔。另外乙個選擇是讓基類把它們需要的狀態拉進去處理。乙個實現方法是使用服務定位器。

class

superpower

};

這裡spawenparticles需要乙個粒子系統。它從服務定位器獲取了乙個,而不是由外部**主動提供。

MSSQL沙盒模式提權問題總結

恢復對登錄檔的讀寫儲存。dbcc addextendedproc xp regread,xpstar.dll dbcc addextendedproc xp regwrite,xpstar.dll 修復沙盒的保護模式 exec master.xp regwrite hkey local machin...

遊戲程式設計學習 天空盒

天空盒 1.天空的種類 目前描述 天空 的技術主要包括三種型別 平板型天空 sky plane 僅用乙個平板放到頭頂。天空穹 sky dome 放到頭頂的是乙個曲面。天空盒 sky box 放到場景的是乙個立方體。天空盒經常是由六個面組成的立方體,並經常會隨著視點的移動而移動。天空盒將刻畫極遠處人無...

遊戲程式設計模式 命令模式

最近深感 設計對於軟體開發過程中的重要性,所以重新拾起了設計模式,以前學的比較鬆散,理解不夠,這一次本著learning,try,teaching的精神,重新認識和學習設計模式。這一次參考robert nystrom 著的 遊戲程式設計模式 一書,與原先的gof所著的24種設計模式不同,但思想是相通...