如何应用设计模式设计你的足球引擎
原文地址:
http://www.codeproject.com/KB/architecture/applyingpatterns.aspx
作者:An 'OOP' Madhusudanan
譯者:賴(lài)勇浩(http://blog.csdn.net/lanphaday )
譯者說(shuō):這是一篇非常好的文章,有非常棒的例子,非常棒的文筆,非常棒的代碼(VB.net編寫(xiě)的,但你肯定讀得懂),如果你還不懂設(shè)計(jì)模式,那它肯定是最適合你的 DPs 文章之一。
第一部分
解決方案架構(gòu)師:你可以嘗試使用模式
愚蠢的開(kāi)發(fā)者:好的,它像 ActiveX 控件那樣用嗎?"
介紹
關(guān)于本文
本文希望能夠做到
- 以簡(jiǎn)單、可讀的方式向你介紹模式
- 教你如何真正“應(yīng)用”模式(模式易學(xué),但必須有過(guò)硬的設(shè)計(jì)本領(lǐng)才能應(yīng)用它們解決問(wèn)題)
- 讓你認(rèn)清應(yīng)用 Builder、Observer、Strategy和 Decorator(這幾個(gè)可是少數(shù)極常用的模式)模式的時(shí)機(jī)。
- 展示如何用 Observer 模式解決設(shè)計(jì)難題
全文通過(guò)如下內(nèi)容依次推進(jìn)
先決條件
- 你需要懂得一些閱讀和理解 UML 圖的知識(shí)。
代碼使用指南
- 相應(yīng)的 zip 文件包含了代碼、UML設(shè)計(jì)圖(visio 格式)等,你可以使用 Winzip 等壓縮軟件解壓。
簡(jiǎn)說(shuō)設(shè)計(jì)模式
即使對(duì)設(shè)計(jì)模式知之甚少,設(shè)計(jì)師和開(kāi)發(fā)者也會(huì)傾向于重用類(lèi)和對(duì)象間來(lái)簡(jiǎn)化設(shè)計(jì)過(guò)程。簡(jiǎn)言之就是“設(shè)計(jì)模式考慮了多種對(duì)象(類(lèi)、關(guān)系等)間的協(xié)作”,為常見(jiàn)的設(shè)計(jì)問(wèn)題提供解決方案。最為重要的是他們?yōu)樵O(shè)計(jì)師和程序員提供一些“行話(huà)”來(lái)談?wù)撍麄兊脑O(shè)計(jì)。例如你可以告訴你的朋友你使用了 Builder 模式來(lái)解決你項(xiàng)目中的一些問(wèn)題。
Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides[即知名的四人幫(GOF)]為常見(jiàn)的設(shè)計(jì)問(wèn)題提供了一致的分類(lèi)模式。GOF 模式被認(rèn)為是其它所有模式的基礎(chǔ)。
使用模式的基本原則是可重用性。如果你正確理解了以模式為中心的軟件工程概念,當(dāng)遇到問(wèn)題時(shí)你就不會(huì)重復(fù)發(fā)明輪子。這里有一些關(guān)于設(shè)計(jì)模式的重要觀點(diǎn):
- 設(shè)計(jì)模式不是代碼,實(shí)際上它是一種解決問(wèn)題的方法或模型。
- 設(shè)計(jì)模式是關(guān)于設(shè)計(jì)和對(duì)象間互動(dòng)的,為它們提供解決常見(jiàn)設(shè)計(jì)問(wèn)題的可重用的解決方案。
- 設(shè)計(jì)模式通常可以用 UML 圖來(lái)表示。
真正的動(dòng)手的經(jīng)驗(yàn)可以給你更好的理念。
架構(gòu)(簡(jiǎn)單)足球引擎
假設(shè)你在一家游戲開(kāi)發(fā)公司供職,上頭決定讓你為公司的重要項(xiàng)目——足球游戲引擎做一套解決方案架構(gòu)(很棒,哈哈)。現(xiàn)在由你領(lǐng)導(dǎo)設(shè)計(jì)整個(gè)足球游戲引擎,突然你就多了許多要考慮的事情,比如:
- 在游戲系統(tǒng)中如何標(biāo)識(shí)實(shí)體,
- 如何確定設(shè)計(jì)問(wèn)題所在,
- 如何應(yīng)用模式來(lái)搞定你的設(shè)計(jì)說(shuō)明書(shū)?
標(biāo)識(shí)實(shí)體
首先,需要標(biāo)識(shí)游戲引擎中的所有對(duì)象。因此你要想像一下終端用戶(hù)將如何使用這個(gè)系統(tǒng),現(xiàn)在假設(shè)終端用戶(hù)將用以下序列來(lái)操作游戲(先簡(jiǎn)單化):
- 打開(kāi)游戲
- 選擇兩支球隊(duì)
- 配置球員
- 選擇球場(chǎng)
- 開(kāi)始
系統(tǒng)是可能有若干個(gè)球場(chǎng)(PlayGrounds)和球隊(duì)(Teams)。系統(tǒng)中實(shí)際上起碼有這些對(duì)象:
- 球員(Player),踢球的人。
- 球隊(duì)(Team),包含若干球員。
- 球(Ball),球員所持有的物體。
- 球場(chǎng)(PlayGround),比賽進(jìn)行的地方。
- 裁判(Referee),球場(chǎng)上控制比賽的人。
另外,游戲引擎中還有一些邏輯對(duì)象,如:
- 游戲(Game),定義了足球比賽,制定球隊(duì)、球、裁判、球場(chǎng)等。
- 同時(shí)模擬一個(gè)或多個(gè)比賽。
- 球隊(duì)策略(TeamStragy),比賽時(shí)決定球隊(duì)的策略
這只是對(duì)系統(tǒng)的一個(gè)抽象形式,下圖表示了系統(tǒng)中的類(lèi)的多樣性和它們之間的接連關(guān)系(“has”)。其中箭頭表示了閱讀的方向次序。游戲引擎(GameEngine)擁有若干比賽(Game);比賽(Game)有三個(gè)裁判、一個(gè)球、兩支球隊(duì)和一個(gè)球場(chǎng);而球隊(duì)又有多個(gè)球員和一個(gè)策略產(chǎn)生器。
?
Fig 1 - High level view
確定設(shè)計(jì)問(wèn)題
現(xiàn)在你要決定
- 這些對(duì)象如何組織
- 如何創(chuàng)建
- 如何在設(shè)計(jì)說(shuō)明書(shū)中確切地闡述當(dāng)他們彼此影響時(shí)的行為。
首先,你得寫(xiě)下對(duì)足球引擎的最小描述來(lái)確定設(shè)計(jì)問(wèn)題,例如下面是是對(duì)我們之前討論的一對(duì)象的設(shè)計(jì)問(wèn)題
- 足球(Ball)
- 當(dāng)球的位置變化,所有的球員和裁判應(yīng)當(dāng)能夠立即感知。
- 球隊(duì)與球隊(duì)策略(Team and TeamStrategy)
- 在比賽中,終端用戶(hù)可以改變球隊(duì)的策略(如從進(jìn)攻改為防守)
- 球員(Player)
- 球隊(duì)中的球員還得有一些額外的職責(zé),如前鋒、后衛(wèi)等,應(yīng)該可以在運(yùn)行進(jìn)指派這些職責(zé)。
- 球場(chǎng)(球場(chǎng))
- 每一個(gè)球場(chǎng)要有座位、草皮、觀眾等,而且每一個(gè)球場(chǎng)都應(yīng)該有不同的外觀。
現(xiàn)在讓我們想想該怎么確定模式以解決這些設(shè)計(jì)問(wèn)題
確定要用的模式
再仔細(xì)看看(是的,最好多看幾次)上面確定的設(shè)計(jì)問(wèn)題,現(xiàn)在讓我們想想怎么用設(shè)計(jì)模式來(lái)解決它們。
1: 解決與球(Ball)相關(guān)的設(shè)計(jì)問(wèn)題
首先來(lái)看看關(guān)于球的說(shuō)明,需要設(shè)計(jì)一個(gè)框架使得當(dāng)球的狀態(tài)(位置)變化時(shí)能夠通知所有球員和裁判,以得到球的新?tīng)顟B(tài)(位置),實(shí)際上就是:
特定的設(shè)計(jì)問(wèn)題:當(dāng)球的位置變態(tài),馬上通知所有球員和裁判。
問(wèn)題泛化:當(dāng)主題(這里是指球)改變,所有的依賴(lài)物(在這里是指球員等)能夠自動(dòng)獲得通知并更新。
當(dāng)你遇到這樣的設(shè)計(jì)問(wèn)題,應(yīng)當(dāng)馬上想起 GOF 模式,甚至立馬認(rèn)識(shí)到可以用Observer 模式來(lái)解決問(wèn)題。
觀察者模式(Observer Pattern):定義了對(duì)象間一對(duì)多的依賴(lài)關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)改變,自動(dòng)通知所有依賴(lài)對(duì)象并更新。
在這里我們使用這個(gè)模式是因?yàn)楫?dāng)球的位置變化時(shí)需要通知所有的球員。
2: 解決與球隊(duì)(Team)和球隊(duì)策略(TeamStrategy)相關(guān)的設(shè)計(jì)問(wèn)題
然后,我們來(lái)解決球隊(duì)和球隊(duì)策略的問(wèn)題。像之前討論的那樣,當(dāng)比賽進(jìn)行時(shí),終端用戶(hù)能夠改變他的球隊(duì)的策略(如從進(jìn)攻改為防守)。無(wú)疑地,這意味著我們需要把球隊(duì)策略從球隊(duì)中分離出來(lái)。
特定的設(shè)計(jì)問(wèn)題:在比賽進(jìn)行中終端用戶(hù)能夠改變它的球隊(duì)的策略(例如從進(jìn)攻改為防守)
問(wèn)題泛化:使客戶(hù)(在這里是球隊(duì))能夠獨(dú)立地改變算法(球隊(duì)策略)
你可以選擇 Strategy 模式來(lái)解決上面這個(gè)設(shè)計(jì)問(wèn)題。
策略模式(Strategy Pattern):定義一系列算法,通過(guò)封裝使它們可以互相替換,Strategy模式使用戶(hù)能夠獨(dú)立地改變算法。
3: 解決與球員(Player)相關(guān)的設(shè)計(jì)問(wèn)題
現(xiàn)在讓我們來(lái)完成與球員相關(guān)的設(shè)計(jì)說(shuō)明書(shū)。從我們的問(wèn)題定義可以確定我們需要在運(yùn)行時(shí)為每一個(gè)球員指派不同的職責(zé)(如前鋒、后衛(wèi)等)。這時(shí)候我們可以考慮子類(lèi)化(也就是繼承),通過(guò)創(chuàng)建一個(gè)球員類(lèi),然后從這個(gè)基類(lèi)派生一些類(lèi),如前鋒、后衛(wèi)等。但它的不足是當(dāng)你子類(lèi)化的時(shí)候,你不能從對(duì)象的實(shí)現(xiàn)中分離職責(zé)。
換言之,在我們的案例中子類(lèi)化并非恰當(dāng)?shù)姆椒?#xff0c;因?yàn)槲覀冃枰獜那騿T的實(shí)現(xiàn)中分離類(lèi)似前鋒、中鋒、后衛(wèi)等職責(zé)。原因在于球員在某一時(shí)刻是前鋒,而另一個(gè)時(shí)刻同一個(gè)球員又可以是中鋒。
特定的設(shè)計(jì)問(wèn)題:球隊(duì)中的球員有額外的職責(zé),如前鋒、后衛(wèi)等,而且要能夠在運(yùn)行時(shí)指派。
問(wèn)題泛化:需要在對(duì)象(在這里是指球員)上動(dòng)態(tài)附加額外職責(zé)(如前鋒、中鋒等),而且不可使用子類(lèi)化。
那么你可以選擇 Decorator 模式來(lái)解決這個(gè)設(shè)計(jì)問(wèn)題。
裝飾者模式(Decorator Pattern):在對(duì)象上動(dòng)態(tài)地額外附加職責(zé),Decorator 提供了子類(lèi)化之外的靈活的擴(kuò)展功能。
4: 解決球場(chǎng)(PlayGround)相關(guān)的設(shè)計(jì)問(wèn)題
如果看去看看球場(chǎng)的說(shuō)明,可以發(fā)現(xiàn)球場(chǎng)的外觀由多個(gè)子單元(如座位、草皮和觀眾等)決定。球場(chǎng)的外觀根據(jù)這些子單元的不同而不同,因此,我們需要特別的構(gòu)建方式,它可以創(chuàng)建不同的球場(chǎng)。也就是說(shuō)一個(gè)意大利球場(chǎng)應(yīng)該有與英格蘭球場(chǎng)不同的座位結(jié)構(gòu)和草皮,但游戲引擎卻可以通過(guò)調(diào)用相同的函數(shù)族來(lái)創(chuàng)建這些球場(chǎng)。
特定的設(shè)計(jì)問(wèn)題:每個(gè)球場(chǎng)都由座位、草皮和觀眾等構(gòu)成,但它們又有互不相同的外觀。
問(wèn)題泛化:需要從對(duì)象(球場(chǎng))的表示(球場(chǎng)的外觀)分離它的構(gòu)建,還需要使用同樣的構(gòu)建過(guò)程來(lái)創(chuàng)建不同的表示。
創(chuàng)建者模式(Builder Pattern):從復(fù)雜對(duì)象的表示中分離它的構(gòu)建,從而使相同的構(gòu)建過(guò)程能夠創(chuàng)建不同的表示。
現(xiàn)在,你可以選擇 Builder 模式來(lái)解決上面的設(shè)計(jì)問(wèn)題。
第二部分
解決方案架構(gòu)師:我叫你去學(xué)學(xué)模式
愚蠢的開(kāi)發(fā)者:是的,現(xiàn)在我可以用模式開(kāi)發(fā)一個(gè)足球引擎了
解決方案架構(gòu)師:啊?你的意思是?!@@#!
應(yīng)用 Observer 模式
在這一節(jié),我們先深入學(xué)習(xí) Observer 模式,然后應(yīng)用模式來(lái)解決第一個(gè)設(shè)計(jì)問(wèn)題。不知道你還記不記得第一個(gè)設(shè)計(jì)問(wèn)題:
- 當(dāng)球的位置變化,馬上通知所有的球員。
理解 Observer 模式
下面是 Observer 模式的是 UML 類(lèi)圖:
?
Fig 2 - Observer Pattern
下面介紹一下這個(gè)模式的成員:
- 主題(Subject)
Subject類(lèi)提供了掛上和拆卸觀察者的接口,并且持有一序列的觀察者,還有如下函數(shù):
- Attach - 增加一個(gè)新的觀察者到觀察者序列
- Detach - 從觀察者序列中刪除一個(gè)觀察者
- Notify- 當(dāng)發(fā)生變化時(shí),調(diào)用每一個(gè)觀察者的 Update 函數(shù)來(lái)通知它們。
- 具體的主題(ConcreteSubject)
這個(gè)類(lèi)提供了觀察者感興趣的狀態(tài),它通過(guò)父類(lèi)的 Notify 函數(shù)通知所有的觀察者。ConcreteSubject的函數(shù)有:
- GetState - 返回主題的狀態(tài)
- 觀察者(Observer)
Observer類(lèi)為所有的觀察者定義了一個(gè)更新接口,用以接收來(lái)自主題的更新通知,它是一個(gè)抽象類(lèi),可以派生具體的觀察者:
- Update - 這是一個(gè)抽象函數(shù),具體的觀察者會(huì)重載這個(gè)函數(shù)。
- 具體的觀察者(ConcreteObserver)
這個(gè)類(lèi)維護(hù)了一個(gè)主題的引用,用來(lái)在收到通知的時(shí)候接收主題的狀態(tài)。
- Update - 這是具體類(lèi)重載的函數(shù),當(dāng)主題調(diào)用它時(shí),ConcreteObserver 調(diào)用主題的 GetState 函數(shù)來(lái)更新與主題狀態(tài)相關(guān)的信息。
應(yīng)用 Observer 模式
現(xiàn)在讓我們來(lái)看看怎么用這個(gè)模式解決我們的特定問(wèn)題,下圖或許能給你一點(diǎn)啟發(fā):
?
Fig 3 - Solving Our First Design Problem
當(dāng)調(diào)用球的 SetBallPosition 函數(shù)設(shè)置一個(gè)新的位置時(shí),它馬上調(diào)用類(lèi) Ball 中定義的 Notify 函數(shù)。Notify 函數(shù)迭代觀察者序列,并調(diào)用它們的 Update 函數(shù)。當(dāng) Update 函數(shù)被調(diào)用,觀察者就可以通過(guò)調(diào)用 FootBall 類(lèi)的 GetBallPosition 函數(shù)來(lái)得到球的新的狀態(tài)位置。
各部分詳述如下:
Ball (Subject)
下面是類(lèi) Ball 的實(shí)現(xiàn)。
FootBall (ConcreteSubject)
下面是類(lèi) FootBall 的實(shí)現(xiàn)。
IObserver (Observer)
下面是類(lèi) IObserver的實(shí)現(xiàn),它提供了具體的觀察者(Concrete Observers)的接口。
轉(zhuǎn)載于:https://www.cnblogs.com/candybox/archive/2010/08/19/1803444.html
總結(jié)
以上是生活随笔為你收集整理的如何应用设计模式设计你的足球引擎的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Sun Solaris 10 bind
- 下一篇: .Net中的委托