观察者模式
观察者模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主体对象,这个主题对象在状态发生变化时,会通知所有观察者。当一个对象改变需要同时改变其他对象,而且他不知道具体有多少对象需要改变的时候,应该考虑使用观察者模式。
观察者结构图: 使用场景:老板回来通知员工需要进入工作状态。
定义观察者的抽象类:
复制代码 代码如下:
abstract class Observer
{
protected string name;
protected ISubject sub;
public Observer(string name, ISubject sub)
{
this.name = name;
this.sub = sub;
}
public abstract void Update();
}
看NBA|直播|的同事:
复制代码 代码如下:
//使用OO
class NBAObserver : Observer
{
public NBAObserver(string name, ISubject sub)
: base(name, sub)
{ }
public override void Update()
{
//throw new NotImplementedException();
Console.WriteLine("{0} {1}关闭NBA|直播|,继续工作!",sub.SubjectState,name);
}
}
//使用事件和委托
class NBAObserver2
{
private string name;
private ISubject2 sub;
public NBAObserver2(string name, ISubject2 sub)
{
this.name = name;
this.sub = sub;
}
public void CloseStockMarket()
{
Console.WriteLine("{0} {1}关闭NBA|直播|,继续工作!", sub.SubjectState, name);
}
}
看股票的同事:
复制代码 代码如下:
//使用OO
class StockObserver : Observer
{
public StockObserver(string name, ISubject sub) : base(name,sub)
{ }
public override void Update()
{
//throw new NotImplementedException();
Console.WriteLine("{0} {1}关闭股票行情,继续工作!",sub.SubjectState,name);
}
}
//使用事件和委托
class StockObserver2
{
private string name;
private ISubject2 sub;
public StockObserver2(string name, ISubject2 sub)
{
this.name = name;
this.sub = sub;
}
public void CloseNBA()
{
Console.WriteLine("{0} {1}关闭股票行情,继续工作!", sub.SubjectState, name);
}
}
上的身份是订阅者,下面定义发布者:
复制代码 代码如下:
//使用OO
interface ISubject
{
void Attach(Observer observer);
void Detach(Observer observer);
void Notify();
string SubjectState
{
get;
set;
}
}
class Boss : ISubject
{
private IList<Observer> observers = new List<Observer>();
private string action;
public void Attach(Observer observer)
{
observers.Add(observer);
}
public void Detach(Observer observer)
{
observers.Remove(observer);
}
public void Notify()
{
foreach (Observer o in observers)
{
o.Update();
}
}
public string SubjectState
{
get { return action; }
set { action = value; }
}
}
//使用事件和委托
interface ISubject2
{
void Notify();
string SubjectState
{
get;
set;
}
}
delegate void EventHandler();
class Boss2 : ISubject2
{
public event EventHandler Update;
private string action;
public void Notify()
{
Update();
}
public string SubjectState
{
get { return action; }
set { action = value; }
}
}
主函数调用:
复制代码 代码如下:
class Program
{
static void Main(string[] args)
{
//观察者模式OO实现
Boss huhansan = new Boss();
StockObserver tongshi1 = new StockObserver("name1",huhansan);
NBAObserver tonshi2 = new NBAObserver("name2", huhansan);
huhansan.Attach(tongshi1);
huhansan.Attach(tonshi2);
huhansan.SubjectState = "我1回来了";
huhansan.Notify();
//观察者模式c#事件实现
Boss2 huhansan2 = new Boss2();
StockObserver2 tongshi3 = new StockObserver2("name3", huhansan2);
NBAObserver2 tonshi4 = new NBAObserver2("name4", huhansan2);
huhansan2.Update += new EventHandler(tongshi3.CloseNBA);
huhansan2.Update += new EventHandler(tonshi4.CloseStockMarket);
huhansan2.SubjectState = "我2回来了";
huhansan2.Notify();
Console.ReadKey();
}
}
委托就是一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看做是对函数的抽象,是函数的一个类,委托实例代表一个具体的函数,而且一个委托可以搭载多个方法,所有方法被依次唤醒。
1 观察者模式
一个简单的例子,比如说猫叫,老鼠跑,主人被惊醒。
在不知道观察者模式之前,我们的代码可能是这样的。
复制代码 代码如下:
//老鼠类
class Mouse
{
public void Run()
{
Console.WriteLine("老鼠跑了!");
}
}
//主人类
class Master
{
public void Wake()
{
Console.WriteLine("主人醒了!");
}
}
//猫类
class Cat
{
public void Cry ()
{
Console.WriteLine("猫叫了!");
new Mouse().Run();//猫叫的同时,调用老鼠跑的方法。
new Master().Wake();//猫叫的同时,调用主人醒的方法。
}
}
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat();
cat.Cry();
Console.ReadLine();
}
}
这个代码基本上能实现所有的功能。但是,这个方法特别不利用扩展,
试想,如果,猫叫后,狗也叫,那是不是也要在猫叫的方法里重新加入狗叫的方法?
或者说,猫叫后,主人他老婆也醒了,是不是也要在猫叫的方法里加入他老婆醒的方法呢?
显然,这样的代码不利用维护,也不是面向对象的代码。
观察者模式能够很好的解决这个问题。
观察者模式定义对象间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于他的对象都得到通知并自动更新。在我们的例子中,猫和老鼠,主人,狗,主人他老婆是一对多的依赖,当猫叫时,所有依赖于它的对象都会自动执行某个操作。
观察者模式的实现,一般有下面四部分组成。
1.ISubject接口(抽象目标),含方法Notify,Register,UnRegister(名字可以自己任意取名)
2.Subject类(实体目标),实现ISubject接口,一般只有一个
3.IObservable接口(抽象观察者)。
4 Observer类(实体观察者),实现IObservable接口,一般有多个。
观察者模式中的“注册--通知--注销”图示:
1. 观察者(Observer)将自己(Regiester)注册到被观察对象(Subject)中,被观察对象将观察者放在一个容器(Container)。Container一般为Ilist,Arraylist等数据结构,存放多个IObservable接口变量。
2.当被观察对象(Subject)发生变化(如图中的AskPriceChanged)时,容器(Container)中的所有观察者(Observer)都得到通知(Notify 方法),此时观察者会自动执行某些方法。
3.当观察者不想继续观察被观察者时,可以注销(UnRegiester方法)
上面的例子中改造后变成:
1.ISubject接口:
复制代码 代码如下:
interface ISubject
{
void Notify();//主题变动时,通知虽有观察者
void Regiester(IObservable o);//观察者注册
void UnRegiester(IObservable o);//观察者取消注册,此时主题发生任何变动,观察者都不会得到通知。
}
2.Subject 类:
复制代码 代码如下:
class Cat : ISubject
{
private IList<IObservable> observers = new List<IObservable>();
public void Notify()
{
foreach (IObservable o in observers) //逐个通知观察者
{
o.Action();
}
}
public void Regiester(IObservable o)
{
if (o != null || !observers.Contains(o))
{
observers.Add(o);
}
}
public void UnRegiester(IObservable o)
{
if (observers != null && observers.Contains(o))
{
observers.Remove(o);
}
}
public void Cry()
{
Console.WriteLine("猫叫了!");
Notify();
}
}
3. IObservable 接口:
复制代码 代码如下:
interface IObservable
{
void Action();//观察者对主题变动所对应的操作
}
4.Observer类(2个,Mouse和Master)
复制代码 代码如下:
class Mouse : IObservable
{
public void Action()
{
Console.WriteLine("鼠跑了!");
}
}
class Master : IObservable
{
public void Action()
{
Console.WriteLine("主人醒了!");
}
}
5.主程序
复制代码 代码如下:
Mouse mouse = new Mouse();
Master master = new Master();
Cat cat = new Cat();
cat.Regiester(mouse);
cat.Regiester(master);
cat.Cry();
Console.ReadLine();
这样就实现了观察者模式,通过把依赖类注册到主体类中,当主体类发生变化时,所有依赖类都得到了通知。如果需要扩展,比如说象上面例子的狗也叫了,我们可以定义一个狗类,然后在主程序中把狗对象注册到猫类中就可以了。如果不想依赖于猫类,也可以通过UnRegiester方法取消绑定。
同时,这也符合设计中的高内聚,低耦合的原则。
。
复制代码 代码如下:
using System;
using System.Collections.Generic;
using System.Text;
namespace Sample
{
public delegate void CatCallEventHandler();
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat();
Mouse mouse = new Mouse(cat);
Master master = new Master(mouse);
cat.Call();
}
}
class Cat
{
public event CatCallEventHandler catevent;
public void Call()
{
Console.WriteLine("喵喵.....");
catevent();
}
}
class Mouse
{
public event CatCallEventHandler mouseevent;
public Mouse(Cat cat)
{
cat.catevent += new CatCallEventHandler(this.MouseRun);
}
public void MouseRun()
{
Console.WriteLine("老鼠跑");
mouseevent();
}
}
class Master
{
public Master(Mouse mouse)
{
mouse.mouseevent+=new CatCallEventHandler(this.JingXing);
}
public void JingXing()
{
Console.WriteLine("主人被惊醒");
}
}
}
相关推荐:
AJAX 自学练习 请求与显示
Aspx/Asp.net 防注入程序 V1.0
xhEditor的异步载入实现代码
JavaScript 复制功能代码 兼容多浏览器
asp 取一个数的整数 但不是四舍五入,只要有小数,就取大于这个数的整数
javascript 弹出层居中效果的制作
Mootools 1.2教程 滚动条(Slider)
js trim函数 去空格函数与正则集锦
jsp form表单方法示例
javascript 随机抽奖程序代码
IIS6中配置PHP的方法 200911
Javascript结合css实现网页换肤功能
3步搞定纯真IP数据导入到MySQL的方法详解
JQuery 绑定事件时传递参数的实现方法
oracle 更改数据库名的方法
Mootools 1.2教程(21)——类(二)
Flex 获得png透明截图的问题和解决方法
js 覆盖和重载 函数
mysql 备份与迁移 数据同步方法
sqlserver 日志恢复方法(搞定drop和truncate)
PHP小程序自动提交到自助友情连接
document.onreadystatechange事件的用法分析
ASP连接SQL2005数据库连接代码
JavaScript 核心参考教程 内置对象
在oracle 数据库中查看一个sql语句的执行时间和SP2-0027错误
hh.exe 隐藏参数 chm反编译命令参数
解决jquery .ajax 在IE下卡死问题的解决方法
不一样的文字闪烁 轮番闪烁
3389 远程桌面连接的使用技巧
发展海外业务 海外邮件重点出击
使用regini.exe修改注册表命令
JavaScript 表格高亮类的应用[高级]
php self,$this,const,static,-&gt;的使用
javascript 必知必会之closure
C# 面向对象的基本原则
MSSQL 数据库同步教程
JavaScript iframe的相互操作浅析
JS 截取字符串substr 和 substring方法的区别
JQuery 图片延迟加载并等比缩放插件
javascript Keycode对照表
ThinkPHP php 框架学习笔记
Oracle 中文字段进行排序的sql语句
Jquery 获取表单text,areatext,radio,checkbox,select值的代码
js 冒泡事件与事件监听使用分析
JavaScript window.setTimeout() 的详细用法
JavaScript Sort 表格排序
编写的vs2005水晶报表程序在vs2008下正常使用的一些实现方法
C# TreeView控件使用代码
asp.net 页面转向 Response.Redirect, Server.Transfer, Server.Execute的区别
JavaScript 工具库 Cloudgamer JavaScript Library v0.1 发布