观察者模式 Observer Pattern — 三国演义之超级间谍战 — 美女貂蝉的故事
说明:我也是初学者,希望大家能提出宝贵意见。另外转载请注明作者左光和出处博客园,毕竟花费了很长时间才完成。
前言:
在网上搜索一下 MVC 模式,大部分都是和 Struts 、Spring 这些东东有关的,好像一说到MVC 模式,就必须和框架有关似的,费了半天劲仍然是晕晕乎乎,好在其中的观察者模式比较好理解,这两天正好又在听袁阔成的评书《三国演义》,于是就结合三国故事和观察者模式写下这一篇《三国演义之超级间谍战 — 美女貂蝉的故事》,希望大家多给一点指教。
情节:
这一次讲的故事情节很简单,但是充满了谋略和斗争。大体意思就是三国初期,曹刘孙三家在徐州联手消灭了吕布,但是自己也伤了元气。而此时袁术得了传国玉玺,在淮南称帝,兵精将广,图谋不轨,对三家威胁都很大。于是曹刘孙三家在一起开了个会,决定派遣一名超级间谍打入到袁术身旁,监视他的一举一动,这样的话一旦袁术想干什么坏事,他们就可以立刻知道并做出相应的调整,知己知彼百战百胜嘛。
计是好计,问题是派谁去当这个超级间谍呢?正当大家愁眉苦脸的时候,美女貂蝉自告奋勇,想当年董卓那么厉害都让我灭了,何况一个小小的袁术呢?大家一听,说的有理,于是就把貂蝉献给了袁术当了妃子。另外三家还各派出一名小奸细常住在淮南城内,他们的任务是当联络员,貂蝉有什么情报总不能自己曹刘孙三家挨个跑着送吧?直接丢给各国联络员,然后让他们通知各自的主公就 OK 了!而三家只要一接到各自奸细的通知,就会立即做出反应。
还有一个小插曲,袁术虽然收下了貂蝉,但是对她看管很严,大大方方地把情报送出去不太可能,逼不得以,貂蝉自己设计了一套密码来传递情报,虽然加密方法没有公开,但是她想总有人可以破解了吧?没错,对诸葛亮来说就是小菜一碟,从此袁术穿什么内裤曹刘孙三家都知道得清清楚楚。
分析:
下面我们用 观察者模式 来分析一下上面这个故事
1、美女貂蝉:貂蝉在观察者模式中叫做被观察者(Subject),主要任务是独立的管理后台数据和业务逻辑,同时尽可能不受前台客户端界面变化的影响。当然,还要负责登记或者注销各个观察者。
在这个故事里,貂蝉仅仅维护了一个数据 ,就是情报 — 私有变量 info ;另外还拥有一个业务逻辑,是用来加密 info 的方法 Reverse(string str) 。每次得到新的情报,她就会先加密,然后立刻找到在自己这登记过的联络员,让这些联络员通知自己的主公应变。
情报一旦发送出去, 貂蝉的任务就算完成了,具体曹刘孙三家怎么应对,是打是降还是另有其他方法,那是三家自己的事情,和她貂蝉就没什么关系了。
2、曹刘孙三家:曹刘孙三家在观察者模式里叫做观察者,主要任务就是从界面上用“各种方式”即时的反映出 被观察者,所谓“各种方式”就是说用字符、图形、声音都可以表示同样数据,外在表现不同而已,本质都是一些数据。所谓“即时”,就是说只要 被观察者 发生变化, 观察者 也会立刻跟着变化,用行话应该叫做刷新 Update吧。
在这个故事里,我们可以看到运行结果中,每次貂蝉有什么新的情报,三家都会在屏幕上显示出来,虽然很简单,但 他们确实是用各自不同的方式表示了同样的数据 。
下面来看看代码是怎么描述这个故事的吧。
类文件 Observer.cs
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace ObserverPattern
{
//这个类描述 美女间谍貂蝉,她是一个 被观察者 或者说是 消息发布者
//她的任务只是负责发布消息,观察者 得到消息后怎么处理就不是她操心的事情了
public class Diao_Model
{
ArrayList spyList = new ArrayList();
string info;
//构造函数
public Diao_Model()
{
Console.WriteLine("貂蝉:每次危难关头,还得看小女子貂蝉出马!\n");
}
//登记观察者
public void RegisterObserver(Observer o)
{
Console.WriteLine("{0}的奸细来了..",o.Name);
spyList.Add(o);
}
//移除观察者
public void RemoveObserver(Observer o)
{
Console.WriteLine("{0}不想干了,把奸细撤走了..", o.Name);
spyList.Remove(o);
}
//设置和获得情报
public string Info
{
get
{
return info;
}
set
{
Console.WriteLine("貂蝉:得到情报‘{0}’!\n", value);
info = Reverse(value);
Notify();//每次得到情报后就立刻通知
}
}
//情报不加密送不出去呀,实际上就是颠倒顺序
//这是貂蝉自己的业务逻辑,外部是不知道的
private string Reverse(string str)
{
string temp = null;
for (int i = str.Length - 1; i >= 0; i--)
temp = temp + str[i];
Console.WriteLine("情报已经被加密为:‘{0}’,这是内部逻辑,别人都不知道\n", temp);
return temp;
}
// 当数据改变时,通知各个Observer,做出相应的反应
private void Notify()
{
Console.WriteLine("貂蝉:情报‘{0}’已经通过奸细送往各国,他们怎么办我就不管了.\n", info);
foreach (Object spy in spyList)
{
Observer o = (Observer)spy;
o.Update(this);
}
}
}
//==========================================================================
//抽象观察者
public interface Observer
{
string Name { get;}
void Update(Diao_Model model);
}
//曹操 观察者 之一
public class Cao_View : Observer
{
string name = "曹操";
public string Name
{
get { return name; }
}
public void Update(Diao_Model model)
{
Console.WriteLine("曹孟德:‘{0}’是什么意思?貂蝉小妞到底想不想干了?", model.Info);
Console.WriteLine("曹孟德:立刻进入一等战备,随时迎敌!\n");
}
}
//刘备 观察者 之一,诸葛亮竟然会破解密码!
public class Liu_View : Observer
{
string name = "刘备";
public string Name
{
get { return name; }
}
public void Update(Diao_Model model)
{
Console.WriteLine("刘玄德:这密码是什么意思呀?快快请诸葛先生来.");
Console.WriteLine("诸葛亮:主公勿慌,密码已经破译了,貂蝉说‘{0}’\n", Reverse(model.Info));
}
private string Reverse(string str)
{
string temp = null;
for (int i = str.Length - 1; i >= 0; i--)
temp = temp + str[i];
return temp;
}
}
//孙策 观察者 之一
public class Sun_View : Observer
{
string name = "孙策";
public string Name
{
get { return name; }
}
public void Update(Diao_Model model)
{
Console.WriteLine("孙策:‘{0}’??貂蝉发一堆乱码做甚?!", model.Info);
Console.WriteLine("孙策:不管怎样,还是准备一下好,擂鼓升帐!!!");
}
}
}
客户端 Client.cs
using System.Collections.Generic;
using System.Text;
namespace ObserverPattern
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("故事开始了..\n");
//创建 被观察者 貂蝉
Diao_Model diaochan = new Diao_Model();
//创建各国奸细
Cao_View cao = new Cao_View();
Liu_View liu = new Liu_View();
Sun_View sun = new Sun_View();
//貂蝉开始联络各国奸细并登记造册
Console.WriteLine("貂蝉开始联络各国奸细\n");
diaochan.RegisterObserver(cao);
diaochan.RegisterObserver(liu);
diaochan.RegisterObserver(sun);
Console.WriteLine();
//貂蝉得到一条重要信息
diaochan.Info = "袁术得了重感冒";
Console.WriteLine();
//孙策不想干了,他的奸细被貂蝉注销了
diaochan.RemoveObserver(sun);
Console.WriteLine();
//貂蝉又得到一条重要信息
diaochan.Info = "袁术有骑兵10万";
Console.WriteLine();
Console.Read();
}
}
}
运行效果如下: