这是传说,必须迷恋它:观察者模式
观察者模式又叫发布-订阅模式。它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生改变时,会通知所有观察者对象,使它们能够自动更新自己。
从上面的描述中,我们可以抽象出主题Subject类和观察者Observer类,”一对多“的关系告诉我们,观察者可以有多个,而主题只有一个。主题有一个很有趣的东西叫”状态“,因为它的变化会唤醒多个观察者”自动更新自己“。
举例来说,我们上网常用的某种下载工具,当文件下载结束时,下载结束的提示音(Toner)响起,下载日志(Logger)里写入文件下载成功时的时间。这里我们可以抽象出被下载的文件为主题Subject,它的标志是否下载成功IsDownloaded是”状态“。提示音Toner和下载日志Logger为观察者。我们用c#里的委托和事件来实现。好了,code is cheap.上代码了。
1.类图:
2.代码
Code
using System;
namespace ObserverPattern
{
/// <summary>
/// 抽象主题,如果主题只有一个,可以不定义,这里是为了扩展需要
/// </summary>
interface ISubject
{
void Notify();
}
/// <summary>
/// 包含事件数据的类,它是在事件触发时,传递数据用的
/// </summary>
public class DownloadEventArgs : EventArgs
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
/// <summary>
/// 主题
/// </summary>
public class DownloadingFile : ISubject
{
private string fileName;
/// <summary>
/// 被下载文件名
/// </summary>
public string FileName
{
get { return fileName; }
set { fileName = value; }
}
private bool isDownload;
/// <summary>
/// 是否已经下载
/// </summary>
public bool IsDownload
{
get { return isDownload; }
set { isDownload = value; }
}
public delegate void DownloadFileEventHandler(object sender, DownloadEventArgs args); //定义委托
public event DownloadFileEventHandler downloadFileOp; //声明事件
public void Notify()
{
Console.WriteLine("Now tell the observers");
if (downloadFileOp != null && !string.IsNullOrEmpty(this.FileName) && this.isDownload) //文件下载完成,发出通知
{
DownloadEventArgs dea = new DownloadEventArgs();
dea.Name = this.FileName;
downloadFileOp(this, dea);
}
}
}
/// <summary>
/// 抽象观察者
/// </summary>
public abstract class Observer
{
public abstract void Update(object sender, DownloadEventArgs e); // 当主题发生改变时,通知各观察者更新自己,实际的观察者中,方法名不一定叫Update
}
/// <summary>
/// 提示音
/// </summary>
public class Toner : Observer
{
public override void Update(object sender, DownloadEventArgs e)
{
Console.WriteLine("{0} is downloaded successful.", e.Name);
}
}
/// <summary>
/// 下载日志
/// </summary>
public class Logger : Observer
{
public override void Update(object sender, DownloadEventArgs e)
{
Console.WriteLine("{0} is downloaded successful at {1}.", e.Name, DateTime.Now.ToString());
}
}
/// <summary>
/// 客户端调用
/// </summary>
public class Program
{
static void Main(string[] args)
{
DownloadingFile df = new DownloadingFile();
df.FileName = "visual studio 2008";
df.downloadFileOp += new DownloadingFile.DownloadFileEventHandler(new Toner().Update);
df.downloadFileOp += new DownloadingFile.DownloadFileEventHandler(new Logger().Update);
// vs2008下载完既发出提示音,也写进下载日志
df.IsDownload = true;
df.Notify();
df = new DownloadingFile();
df.FileName = "sql server 2008";
df.downloadFileOp += new DownloadingFile.DownloadFileEventHandler(new Logger().Update);
// sql server 2008下载完只写进下载日志
df.IsDownload = true;
df.Notify();
Console.Read();
}
}
}
using System;
namespace ObserverPattern
{
/// <summary>
/// 抽象主题,如果主题只有一个,可以不定义,这里是为了扩展需要
/// </summary>
interface ISubject
{
void Notify();
}
/// <summary>
/// 包含事件数据的类,它是在事件触发时,传递数据用的
/// </summary>
public class DownloadEventArgs : EventArgs
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
/// <summary>
/// 主题
/// </summary>
public class DownloadingFile : ISubject
{
private string fileName;
/// <summary>
/// 被下载文件名
/// </summary>
public string FileName
{
get { return fileName; }
set { fileName = value; }
}
private bool isDownload;
/// <summary>
/// 是否已经下载
/// </summary>
public bool IsDownload
{
get { return isDownload; }
set { isDownload = value; }
}
public delegate void DownloadFileEventHandler(object sender, DownloadEventArgs args); //定义委托
public event DownloadFileEventHandler downloadFileOp; //声明事件
public void Notify()
{
Console.WriteLine("Now tell the observers");
if (downloadFileOp != null && !string.IsNullOrEmpty(this.FileName) && this.isDownload) //文件下载完成,发出通知
{
DownloadEventArgs dea = new DownloadEventArgs();
dea.Name = this.FileName;
downloadFileOp(this, dea);
}
}
}
/// <summary>
/// 抽象观察者
/// </summary>
public abstract class Observer
{
public abstract void Update(object sender, DownloadEventArgs e); // 当主题发生改变时,通知各观察者更新自己,实际的观察者中,方法名不一定叫Update
}
/// <summary>
/// 提示音
/// </summary>
public class Toner : Observer
{
public override void Update(object sender, DownloadEventArgs e)
{
Console.WriteLine("{0} is downloaded successful.", e.Name);
}
}
/// <summary>
/// 下载日志
/// </summary>
public class Logger : Observer
{
public override void Update(object sender, DownloadEventArgs e)
{
Console.WriteLine("{0} is downloaded successful at {1}.", e.Name, DateTime.Now.ToString());
}
}
/// <summary>
/// 客户端调用
/// </summary>
public class Program
{
static void Main(string[] args)
{
DownloadingFile df = new DownloadingFile();
df.FileName = "visual studio 2008";
df.downloadFileOp += new DownloadingFile.DownloadFileEventHandler(new Toner().Update);
df.downloadFileOp += new DownloadingFile.DownloadFileEventHandler(new Logger().Update);
// vs2008下载完既发出提示音,也写进下载日志
df.IsDownload = true;
df.Notify();
df = new DownloadingFile();
df.FileName = "sql server 2008";
df.downloadFileOp += new DownloadingFile.DownloadFileEventHandler(new Logger().Update);
// sql server 2008下载完只写进下载日志
df.IsDownload = true;
df.Notify();
Console.Read();
}
}
}
正像上面代码里注释的那样,实际的项目中,观察者更新自己的方法名并不一定叫Update,我们改进一下代码中的方法名,让它们看上去更实际一些:
Code
using System;
namespace ObserverPattern
{
/// <summary>
/// 抽象主题,如果主题只有一个,可以不定义,这里是为了扩展需要
/// </summary>
interface ISubject
{
void Notify();
}
/// <summary>
/// 包含事件数据的类,它是在事件触发时,传递数据用的
/// </summary>
public class DownloadEventArgs : EventArgs
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
/// <summary>
/// 主题
/// </summary>
public class DownloadingFile : ISubject
{
private string fileName;
/// <summary>
/// 被下载文件名
/// </summary>
public string FileName
{
get { return fileName; }
set { fileName = value; }
}
private bool isDownload;
/// <summary>
/// 是否已经下载
/// </summary>
public bool IsDownload
{
get { return isDownload; }
set { isDownload = value; }
}
public delegate void DownloadFileEventHandler(object sender, DownloadEventArgs args); //定义委托
public event DownloadFileEventHandler downloadFileOp; //声明事件
public void Notify()
{
Console.WriteLine("Now tell the observers");
if (downloadFileOp != null && !string.IsNullOrEmpty(this.FileName) && this.isDownload) //文件下载完成,发出通知
{
DownloadEventArgs dea = new DownloadEventArgs();
dea.Name = this.FileName;
downloadFileOp(this, dea);
}
}
}
/// <summary>
/// 提示音
/// </summary>
public class Toner
{
/// <summary>
/// 提示音响起
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void Ring(object sender, DownloadEventArgs e)
{
Console.WriteLine("{0} is downloaded successful.", e.Name);
}
}
/// <summary>
/// 下载日志
/// </summary>
public class Logger
{
/// <summary>
/// 写日志
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void WriteLog(object sender, DownloadEventArgs e)
{
Console.WriteLine("{0} is downloaded successful at {1}.", e.Name, DateTime.Now.ToString());
}
}
/// <summary>
/// 客户端调用
/// </summary>
public class Program
{
static void Main(string[] args)
{
DownloadingFile df = new DownloadingFile();
df.FileName = "visual studio 2008";
df.downloadFileOp += new DownloadingFile.DownloadFileEventHandler(new Toner().Ring); // 是Ring而不是Update了
df.downloadFileOp += new DownloadingFile.DownloadFileEventHandler(new Logger().WriteLog);
// vs2008下载完既发出提示音,也写进下载日志
df.IsDownload = true;
df.Notify();
df = new DownloadingFile();
df.FileName = "sql server 2008";
df.downloadFileOp += new DownloadingFile.DownloadFileEventHandler(new Logger().WriteLog);
// sql server 2008下载完只写进下载日志
df.IsDownload = true;
df.Notify();
Console.Read();
}
}
}
using System;
namespace ObserverPattern
{
/// <summary>
/// 抽象主题,如果主题只有一个,可以不定义,这里是为了扩展需要
/// </summary>
interface ISubject
{
void Notify();
}
/// <summary>
/// 包含事件数据的类,它是在事件触发时,传递数据用的
/// </summary>
public class DownloadEventArgs : EventArgs
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
/// <summary>
/// 主题
/// </summary>
public class DownloadingFile : ISubject
{
private string fileName;
/// <summary>
/// 被下载文件名
/// </summary>
public string FileName
{
get { return fileName; }
set { fileName = value; }
}
private bool isDownload;
/// <summary>
/// 是否已经下载
/// </summary>
public bool IsDownload
{
get { return isDownload; }
set { isDownload = value; }
}
public delegate void DownloadFileEventHandler(object sender, DownloadEventArgs args); //定义委托
public event DownloadFileEventHandler downloadFileOp; //声明事件
public void Notify()
{
Console.WriteLine("Now tell the observers");
if (downloadFileOp != null && !string.IsNullOrEmpty(this.FileName) && this.isDownload) //文件下载完成,发出通知
{
DownloadEventArgs dea = new DownloadEventArgs();
dea.Name = this.FileName;
downloadFileOp(this, dea);
}
}
}
/// <summary>
/// 提示音
/// </summary>
public class Toner
{
/// <summary>
/// 提示音响起
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void Ring(object sender, DownloadEventArgs e)
{
Console.WriteLine("{0} is downloaded successful.", e.Name);
}
}
/// <summary>
/// 下载日志
/// </summary>
public class Logger
{
/// <summary>
/// 写日志
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void WriteLog(object sender, DownloadEventArgs e)
{
Console.WriteLine("{0} is downloaded successful at {1}.", e.Name, DateTime.Now.ToString());
}
}
/// <summary>
/// 客户端调用
/// </summary>
public class Program
{
static void Main(string[] args)
{
DownloadingFile df = new DownloadingFile();
df.FileName = "visual studio 2008";
df.downloadFileOp += new DownloadingFile.DownloadFileEventHandler(new Toner().Ring); // 是Ring而不是Update了
df.downloadFileOp += new DownloadingFile.DownloadFileEventHandler(new Logger().WriteLog);
// vs2008下载完既发出提示音,也写进下载日志
df.IsDownload = true;
df.Notify();
df = new DownloadingFile();
df.FileName = "sql server 2008";
df.downloadFileOp += new DownloadingFile.DownloadFileEventHandler(new Logger().WriteLog);
// sql server 2008下载完只写进下载日志
df.IsDownload = true;
df.Notify();
Console.Read();
}
}
}
作者:Jeff Wong
出处:http://jeffwongishandsome.cnblogs.com/
本文版权归作者和博客园共有,欢迎围观转载。转载时请您务必在文章明显位置给出原文链接,谢谢您的合作。