觀察者設計模式——貓捉老鼠
觀察者設計模式
通過貓捉老鼠這個例子來弄清楚委託和事件並且對他們的用途有更深的認識。
在這裡,貓是被觀察者,老鼠是觀察者。當觀察者發生動作時,觀察者對應的就會有相應的動作,比如貓開始移動了,老鼠就相應地都逃跑了。又比如在遊戲中,被觀察者是一個開始按鈕,當它被點選的時候,觀察者(美術資源、音樂資源、場景資源等)就會開始載入。
貓捉老鼠
首先我們定義一個Cat類
class Cat
{
private string name;
private string color;
public Cat(string name, string color)
{
this.name = name;
this.color = color;
}
public void CatComing()
{
Console.WriteLine(color+"的貓"+name+"來了");
}
}
還需要一個Mouse類
class Mouse
{
private string name;
private string color;
public Mouse(string name,string color,Cat cat)
{
this.name = name;
this.color = color;
}
public void RunAway()
{
Console.WriteLine(color+"的老鼠"+name+"正在逃跑");
}
}
然後我們現在主函式裡建立物件
static void Main(string[] args)
{
Cat cat = new Cat("湯姆","灰色");
Mouse mouse1 = new Mouse("傑瑞","黃色",cat);
Mouse mouse2 = new Mouse("米老鼠","灰色",cat);
Console.ReadKey();
}
現在我們需要讓貓來了的時候,老鼠就會開始逃跑,所以可以將Runaway方法放到CatComing方法裡
public void CatComing(Mouse mouse1,Mouse mouse2)
{
Console.WriteLine(color+"的貓"+name+"來了");
mouse1.RunAway();
mouse2.RunAway();
}
現在這個貓捉老鼠的程式我們就完成了,但是如果這時候又有新的老鼠加進去,我們就需要再次修改CatComing方法。在程式設計中,一個模組完成之後,我們儘量不要去修改這個模組,當有新的需求加進來時,我們只需要建立新的物件,方法不用修改,這可以減少很多工作量。
所以我們需要再次修改這個模組,這時候我們可以使用委託來指向CatComing方法。
class Cat
{
private string name;
private string color;
public Cat(string name, string color)
{
this.name = name;
this.color = color;
}
//public void CatComing(Mouse mouse1,Mouse mouse2)
public void CatComing()
{
Console.WriteLine(color+"的貓"+name+"來了");
//mouse1.RunAway();
//mouse2.RunAway();
//將這個方法委託給CatCome
if (CatCome!=null)
{
CatCome();
}
}
public Action CatCome; //宣告一個委託
將方法委託給CatCome之後,我們在主函式裡每建立一個Mouse物件,就使用一次委託。
static void Main(string[] args)
{
Cat cat = new Cat("湯姆","灰色");
Mouse mouse1 = new Mouse("傑瑞","黃色",cat);
cat.CatCome += mouse1.RunAway;
Mouse mouse2 = new Mouse("米老鼠","灰色",cat);
cat.CatCome += mouse2.RunAway;
Console.ReadKey();
}
現在的程式比之前的就簡潔很多了,我們不需要重複的修改方法就能夠達到目的,只需要每建立一個物件就使用一次委託。但是這個程式還能夠修改,我們可以將使用委託這個步驟放到Mouse的構造方法裡,這樣每次建立物件的時候,構造方法就會自動呼叫。
public Mouse(string name,string color,Cat cat)
{
this.name = name;
this.color = color;
cat.CatCome += this.RunAway;
}
static void Main(string[] args)
{
Cat cat = new Cat("湯姆","灰色");
Mouse mouse1 = new Mouse("傑瑞","黃色",cat);
Mouse mouse2 = new Mouse("米老鼠","灰色",cat);
cat.CatComing();
Console.ReadKey();
}
這時候這個程式就完成了,並且有新需求時,也不用再修改其他的模組,只需要建立新的物件就可以了。但是CatCome這個委託我們可以修改為事件。
public event Action CatCome; //宣告一個事件
作用是什麼呢?宣告為一個事件之後,事件就不能夠在類的外部呼叫,只能夠增加新的方法。但是修改成事件之後不需要修改任何東西,因為事件和委託的用法幾乎一樣。
當宣告一個事件之後,我們把宣告事件叫做釋出一個事件,將增加新的方法叫做訂閱事件。
這是整個程式的原始碼
//貓
class Cat
{
private string name;
private string color;
public Cat(string name, string color)
{
this.name = name;
this.color = color;
}
//public void CatComing(Mouse mouse1,Mouse mouse2)
public void CatComing()
{
Console.WriteLine(color+"的貓"+name+"來了");
//mouse1.RunAway();
//mouse2.RunAway();
//將這個方法委託給CatCome
if (CatCome!=null)
{
CatCome();
}
}
public event Action CatCome; //宣告一個事件
}
//老鼠
class Mouse
{
private string name;
private string color;
public Mouse(string name,string color,Cat cat)
{
this.name = name;
this.color = color;
cat.CatCome += this.RunAway; //將自身的逃跑方法註冊到事件裡
}
public void RunAway()
{
Console.WriteLine(color+"的老鼠"+name+"正在逃跑");
}
}
//主類
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat("湯姆","灰色");
Mouse mouse1 = new Mouse("傑瑞","黃色",cat);
//cat.CatCome += mouse1.RunAway;
Mouse mouse2 = new Mouse("米老鼠","灰色",cat);
//cat.CatCome += mouse2.RunAway;
cat.CatComing();
//cat.CatComing(mouse1,mouse2);
Console.ReadKey();
}
}
通過這個案例,我們知道一個程式不是一次性就能夠完成的,它需要經過很多次的修改才能達到很完美的狀態。所以我們在寫程式的時候,不需要想著一次性就寫的最完美,可以先將基本功能寫出來,根據新的需求再在這個基礎上修改它,一直修改到符合需求。