观察者设计模式——猫捉老鼠
观察者设计模式
通过猫捉老鼠这个例子来弄清楚委托和事件并且对他们的用途有更深的认识。
在这里,猫是被观察者,老鼠是观察者。当观察者发生动作时,观察者对应的就会有相应的动作,比如猫开始移动了,老鼠就相应地都逃跑了。又比如在游戏中,被观察者是一个开始按钮,当它被点击的时候,观察者(美术资源、音乐资源、场景资源等)就会开始加载。
猫捉老鼠
首先我们定义一个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();
}
}
通过这个案例,我们知道一个程序不是一次性就能够完成的,它需要经过很多次的修改才能达到很完美的状态。所以我们在写程序的时候,不需要想着一次性就写的最完美,可以先将基本功能写出来,根据新的需求再在这个基础上修改它,一直修改到符合需求。