遊戲程式設計模式(Game Programming Patterns)的C#&Unity練習二:觀察者模式
觀察者模式
核心描述:“在物件間定義一種 一對多的依賴關係,以便當某個物件的情況發生改變時,與它存在依賴關係的所有物件都能收到通知,並自動進行更新。”
知識點:
1.複習了“繼承”和“多型”,包括讓子類以介面的身份進行活動。子類可以直接使用父類的方法。
2.將觀察者模式分為觀察者和被觀察者。觀察者的身份是一個標籤,用介面來實現,繼承了這個介面的類都成為了一個觀察者。被觀察者是一項功能,用被觀察者類來實現,繼承了這個類的派生類都具備被觀察者的能力。
實現流程:
1.建立一個介面IObSevers,用作於觀察者身份的標籤,建立ModeObSevers和AchievementsObSevers作為兩個觀察者。
2.建立一個類Subject,用於實現被觀察者的功能,包括觀察者列表的維護和通知功能。建立一個類PhysicsSubject作為實際的被觀察者,繼承於Subject。
3.將ModeObSevers和AchievementsObSevers加入到PhysicsSubject的觀察者列表中,由PhysicsSubject對前面兩個觀察者發起通知。
首先要建立一個介面IObSevers:
/// <summary>
/// 所有繼承了該介面的子類,都變成了一個觀察者,可以直接在被觀察者的觀察者列表中處理,這個處理的過程是面向物件多型的一種。
/// </summary>
public interface IObSevers {
/// <summary>
/// 被觀察者直接呼叫觀察者的該方法,來表示通知的這個過程。
/// </summary>
/// <param name="log"></param>
void OnNotify(string log);
}
上面的介面定義了一個用來“通知”的方法,接下來需要完成一個呼叫這個通知的類。
實現呼叫這個“通知”的類:
public class Subject {
/// <summary>
/// 這是一個觀察者列表,用來維護被觀察者需要通知的觀察者物件。
/// </summary>
private List<IObSevers> obSevers = new List<IObSevers>();
/// <summary>
/// 在觀察者列表中新增一個觀察者。這裡物件型別雖然是介面,但實際上是集成了該介面的類以多型的形式出現在這裡。
/// </summary>
/// <param name="ob">觀察者物件</param>
protected void AddObserver(IObSevers ob)
{
obSevers.Add(ob);
}
/// <summary>
/// 在觀察者列表中刪除一個觀察者。
/// </summary>
/// <param name="ob"></param>
protected void RemoveObsever(IObSevers ob)
{
obSevers.Remove(ob);
}
/// <summary>
/// 通知所有的觀察者,引數為事件的型別。
/// </summary>
protected void UpdateNotify()
{
foreach (IObSevers ob in obSevers)
{
if (ob != null)
{
ob.OnNotify("test Log");
}
}
}
}
觀察者和被觀察者的核心已經實現了,接下來需要讓具體的功能模組來完成這樣的觀察者和被觀察者的功能。
首先是在具體的功能模組內實現一個觀察者的功能。
建立一個AchievementsObSevers類,成就係統觀察者。
public class AchievementsObSevers : IObSevers {
/// <summary>
/// 該觀察者收到被觀察者的通知後,應該在該方法內對通知的內容進行判斷並處理。
/// </summary>
/// <param name="log"></param>
public void OnNotify(string log)
{
//在這裡實現被通知後的具體效果。
Debug.Log(log);
}
}
在本文知識點2中提到,所有繼承了IObSevers的類都獲得了一個觀察者的標籤。這個成就係統也獲得了這個標籤。這個成就係統現在就需要等待其他的功能模組發通知,就好像一個觀察者開始持續的觀察一個被觀察者,看這個被觀察者是否會出現特定的行為。
下面來實現這個被觀察者的功能。
建立一個PhysicsSubject類:
public class PhysicsSubject : Subject {
/// <summary>
/// 建立了一個觀察者變數。
/// </summary>
AchievementsObSevers achievements;
/// <summary>
/// 初始化觀察者變數,並把它加入到PhysicsSubject的觀察者列表中
/// 由於PhysicsSubject繼承了Subject,所以子類可以呼叫父類的方法。
/// </summary>
public PhysicsSubject()
{
achievements = new AchievementsObSevers();
this.AddObserver(achievements);
}
/// <summary>
/// 被觀察者通知觀察者列表中的所有觀察者。注意,這裡UpdateNotify()是被this以Subject的身份出現的。
/// </summary>
public void Hello()
{
this.UpdateNotify();
}
}
這個物理模組中,繼承了Subject中的所有可以被繼承的功能。它自己擁有一個觀察者列表,和維護觀察者列表的方法。
private List<IObSevers> obSevers = new List<IObSevers>(); protected void AddObserver(IObSevers ob) { } protected void RemoveObserver(IObSevers ob) { }
它將成就係統加入到他的觀察者列表後,然後有一個方法Hello()讓他向觀察者列表中的所有觀察者呼叫了它們的通知。
這樣觀察者就可以收到這個被觀察物件的通知。