1. 程式人生 > >設計模式遊戲完美開發的學習總結

設計模式遊戲完美開發的學習總結

一、State模式
GOF的解釋”:讓一個物件的行為隨著內部狀態的改變而變化,而該物件也像是換了類一樣”。
書中用State模式實現了場景的轉換。
這是State模式的結構圖。
這裡寫圖片描述

/// <summary>
 2 /// 狀態介面類
 3 /// </summary>
 4 public abstract class State {
 5 
 6     /// <summary>
 7     /// 關聯的狀態擁有者
 8     /// </summary>
 9     protected Context m_Context = null;
10
11 /// <summary> 12 /// 建構函式 13 /// </summary> 14 /// <param name="theContext">狀態擁有者</param> 15 public State(Context theContext) {//建構函式接收Context 類的物件,根據這本書的繪圖習慣,State 那一欄的下面會寫m_Context 16 m_Context = theContext; 17 } 18 19 /// <summary> 20 /// Handle抽象方法
21 /// </summary> 22 /// <param name="Value">引數值</param> 23 public abstract void Handle(int Value); 24 } 複製程式碼

我在原結構圖上添加了m_context,是因為這本書的後面,在一個類的建構函式裡,接收另一個類的物件,然後給這個類的物件賦值,都會在其結構圖上,在這個類的下面會寫另外那個類的物件,這個例子中,就是m_context。
我這樣區別這個問題,是因為,後面的Mediator中介者模式,也在一個介面類的建構函式裡新增一個物件作為引數。在結構圖上,Collegue下面有-mediator。
注意:Context 不是一個介面類,就是說,它不是一個類的集合,後面的中介者模式,Mediator是一個介面,先看看Mediator模式的結構圖。
這裡寫圖片描述


書中原圖是有mediator的。
和state的結構圖很像,從圖上看,區別就是Mediator是作為一個介面的,即是抽象的,它有一個子類來實現它內部的功能。
Colleague類,很像State模式裡的State類,從結構圖的連線關係來看,State模式看起來真的是“狀態模式”,State類只是作為三個子類的介面,供客戶端Context在這三個子類中進行挑選,切換。這裡Mediator可不是客戶端,仔細看結構圖,Mediator是個介面,因為它有實現它的子類。從Mediator 的結構圖連線來看,它真的是“中介模式”,Mediator的子類,把其他需要溝通的類全部包含引用了,這些類的溝通都發生在Mediator的子類中。看看Mediator模式的程式碼:

1 //實現Colleague的類1
 2 public class ConcreateColleague1 : Colleague
 3 {
 4     public ConcreateColleague1( Mediator theMediator) : base(theMediator)
 5     {}
 6 
 7     //執行動作
 8     public void Action()
 9     {
10         //執行後需要通知其他Colleague
11         m_Mediator.SendMessage(this,"Colleage1發出通知");
12     }
13 
14     //Mediator通知請求
15     public override void Request(string Message)
16     {
17         Debug.Log("ConcreateColleague1.Request:"+Message);
18     }
19 }
1 //實現Colleague的類2
 2 public class ConcreateColleague2 : Colleague
 3 {
 4     public ConcreateColleague2( Mediator theMediator) : base(theMediator)
 5     {}
 6         
 7     // 執行動作
 8     public void Action()
 9     {
10         //執行後需要通知其他Colleague
11         m_Mediator.SendMessage(this,"Colleage2發出通知");
12     }
13 
14     //Mediator通知請求
15     public override void Request(string Message)
16     {
17         Debug.Log("ConcreateColleague2.Request:"+Message);
18     }
19 }
1 //實現Mediator介面,並集合管理Colleague物件
 2 public class ConcreteMediator : Mediator
 3 {
 4     ConcreateColleague1 m_Colleague1 = null;
 5     ConcreateColleague2 m_Colleague2 = null;
 6 
 7     public void SetColleageu1( ConcreateColleague1 theColleague )
 8     {
 9         m_Colleague1 = theColleague;
10     }
11 
12     public void SetColleageu2( ConcreateColleague2 theColleague )
13     {
14         m_Colleague2 = theColleague;
15     }
16 
17     // 收到來自Colleague的通知請求
18     public override void SendMessage(Colleague theColleague,string Message)
19     {
20         // 收到Colleague1通知Colleague2
21         if( m_Colleague1 == theColleague)
22             m_Colleague2.Request( Message);
23 
24         // 收到Colleague2通知Colleague1
25         if( m_Colleague2 == theColleague)
26             m_Colleague1.Request( Message);
27     }
28 }

看程式碼,不難發現,Colleague1和Colleague2這兩個類之間並沒有包含引用,它們的溝通和交流都是在ConcreteMediator 類中進行的,這裡和State模式又有區別了,看看State模式的程式碼:

1 /// <summary>
 2 /// 具體狀態A
 3 /// </summary>
 4 public class ConcreteStateA : State {
 5 
 6     /// <summary>
 7     /// 建構函式
 8     /// </summary>
 9     /// <param name="theContext">狀態擁有者</param>
10     public ConcreteStateA(Context theContext) : base(theContext) {
11 
12     }
13 
14     /// <summary>
15     /// Handle
16     /// </summary>
17     /// <param name="Value">引數值</param>
18     public override void Handle(int Value) {
19         Debug.Log("ConcreteStateA.Handle");
20         //根據條件切換到狀態B
21         if(Value > 10) {
22             m_Context.SetState(new ConcreteStateB(m_Context));
23         }
24     }
25 }
4 public class ConcreteStateB:State {
 5 
 6     /// <summary>
 7     /// 建構函式
 8     /// </summary>
 9     /// <param name="theContext"></param>
10     public ConcreteStateB(Context theContext) : base(theContext) {
11 
12     }
13 
14     /// <summary>
15     /// Handle
16     /// </summary>
17     /// <param name="Value">引數值</param>
18     public override void Handle(int Value) {
19         Debug.Log("ConcreteStateB.Handle");
20         //根據條件切換到狀態C
21         if(Value > 20) {
22             m_Context.SetState(new ConcreteStateC(m_Context));
23         }
24     }
25 }
 public class ConcreteStateC:State {
 5 
 6     /// <summary>
 7     /// 建構函式
 8     /// </summary>
 9     /// <param name="theContext"></param>
10     public ConcreteStateC(Context theContext) : base(theContext) {
11 
12     }
13 
14     /// <summary>
15     /// Handle
16     /// </summary>
17     /// <param name="Value">引數值</param>
18     public override void Handle(int Value) {
19         Debug.Log("ConcreteStateC.Handle");
20         //根據條件切換到狀態A
21         if(Value > 30) {
22             m_Context.SetState(new ConcreteStateA(m_Context));
23         }
24     }
25 }

這裡的區別也是由每個模式的特點來決定的,在State模式裡,客戶端的方法和操作,貫穿著State類的三個子類,m_Context.SetState();讓我們感受下。。。。。。這好像是線性貫穿的。
我好像感受到什麼了,一個東西,或者叫object,對外要呈現不同的狀態,它要貫穿遊走在這幾個狀態,線性貫穿有木有,可以用狀態模式來設計。
Mediator 中介者模式,比較好理解,把需要溝通的類,用Mediator 介面的子類(實現類)全部包含,讓它們在裡面溝通,它們自己的類裡並不互相包含引用。而Mediator的物件是在這些需要溝通的子類的介面類在建構函式裡就生成賦值的,也就是說,Mediator的物件也是貫穿在這些個需要溝通的子類裡的,中介者嘛,必須和每個需要溝通的類打交道。
總結下,貫穿,遊離,溝通,切換,有這些動作的物件,都會在它要植入的物件的類的建構函式中進行生成和引用。
再來看看橋接模式,我先畫個結構圖:
這裡寫圖片描述

左邊的兩個方框代表兩個類,右面的帶圓角的方框代表另外的四個類,左邊的兩個類都要用到右邊那四個類的方法,就是說,左邊的都要和右邊的進行連線,左邊和右邊的那一列彼此不連線。這樣的連線方式,就可以用橋接模式。
把左右兩列的類分別抽象化成兩個介面,比如玩家類這個介面,有敵人類和士兵類,炸彈,槍,火箭筒各類武器抽象成一個武器類

1 /// <summary>
 2 /// 武器類群組(武器介面)
 3 /// </summary>
 4 public abstract class IWeapon {
 5 
 6     /// <summary>
 7     /// 武器的擁有者
 8     /// </summary>
 9     protected ICharacter m_WeaponOwner = null;
10 
11     /// <summary>
12     /// 攻擊目標
13     /// </summary>
14     public abstract void Fire(ICharacter theTarget);
15 
16     /// <summary>
17     /// 顯示射擊特效
18     /// </summary>
19     protected void ShowShootEffect() {
20 
21     }
22 
23     /// <summary>
24     /// 顯示子彈特效
25     /// </summary>
26     protected void ShowBulletEffect(Vector3 TargetPosition,float LineWidth,float DisplayTime) {
27 
28     }
29 
30     /// <summary>
31     /// 播放音效
32     /// </summary>
33     protected void ShowSoundEffect(string ClipName) {
34 
35     }
36 }
1 /// <summary>
 2 /// 角色介面
 3 /// </summary>
 4 public abstract class ICharacter {
 5     ...
 6     /// <summary>
 7     /// 使用的武器
 8     /// </summary>
 9     private IWeapon m_Weapon = null;
10 
11     protected void WeaponAttackTarget(ICharacter Target) {
12         m_Weapon.Fire(Target);
13     }
14 
15     /// <summary>
16     /// 攻擊目標
17     /// </summary>
18     public abstract void Attack(ICharacter Target);
19 
20     /// <summary>
21     /// 被其他角色攻擊
22     /// </summary>
23     public abstract void UnderAttack(ICharacter Attacker);
24     ...
25 }

和state模式,中介者模式不同,橋接模式,武器和玩家這兩個介面之間互相包含引用,彼此的建構函式並沒有帶對方介面類的物件作為引數。這是我看出來狀態模式,中介者模式,橋接模式之間的區別。
再總結下:
State模式,一個客戶端,多個狀態類,把狀態類抽象化成一個介面,供客戶端進行呼叫,此時,狀態的介面在其建構函式內,要把客戶端的物件作為引數,並對客戶端物件進行賦值。而多個狀態類的內部有實現狀態切換的方法,供客戶端進行呼叫。
中介者模式,把需要溝通的多個物件抽象成一個介面,中介者也是一個需要實現的介面類,中介者在多個需要溝通的物件例項化時就生成,就是說,多個物件的介面的建構函式是以中介者類為引數的,然後給中介者物件賦值。在中介者的實現類內部,包含所有需要溝通的類,在中介者的實現類內部,讓這些需要溝通的類自己們互相交流。
橋接模式,最簡單,抽象出兩個大介面,比如圖形渲染器例子,在一個接口裡只有一個繪製圖形方法,在需要呼叫繪製方法的類裡定義一個set方法,設定使用哪一個繪製引擎進行繪製。

策略模式,比較像橋接模式,只不過策略模式是客戶端根據需求來呼叫不同的方法。
這裡寫圖片描述

橋接模式Context那一欄裡是個抽象介面。