观察者模式的概念:git
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的全部依赖者都会收到通知并更新。c#
今天咱们就学着用一下这个观察者模式,先想象下这个场景:当一个窗体(主窗体)内的值发生变化时,另外几个窗体内的值也会发生相应的变化。这个最简单的实现方式是,在子窗体类内建立一个公共方法,在主窗体内建立子窗体的实例。当值发生变化时调用子窗体的公共方法。还有一种简单方法是用静态属性,至关于全局变量,这个只能针对小型应用。第一种有一个缺点,当增长子窗体时,咱们须要更改主窗体类的代码。没法实现动态地增长删除对子窗体类中值的更新。这时能够引入观察者模式。
咱们先建立一个winform项目,添加FrmMain,FrmSub1,FrmSub2三个窗体,每一个窗体都添加一个textbox文本框,实现当主窗体中的文本框值发生变化时,其余两个子窗体的值也会发生相应的变化。这里咱们参考《Head First设计模式》,先设计发布者和订阅者(这里我感受仍是叫比较顺口)。代码以下:设计模式
public interface ISubject { /// <summary> /// 注册订阅者 /// </summary> /// <param name="observer"></param> void RegisterObserver(IObserver observer); /// <summary> /// 删除订阅者 /// </summary> /// <param name="observer"></param> void RemoveObserver(IObserver observer); /// <summary> /// 通知订阅者 /// </summary> void NotifyObservers(); } public interface IObserver { /// <summary> /// 观察者对发布者的响应方法 /// </summary> /// <param name="message"></param> void Update(string message); }
修改FrmMain类,使其实现ISubject接口,再给文本框增长change事件,代码以下:this
public partial class FrmMain : Form, ISubject { private string Message { get; set; } private List<IObserver> _observers = new List<IObserver>(); public FrmMain() { InitializeComponent(); } private void FrmMain_Load(object sender, EventArgs e) { FrmSub1 frmSub1 = new FrmSub1(this); FrmSub2 frmSub2 = new FrmSub2(this); frmSub1.Show(); frmSub2.Show(); } /// <summary> /// 文本框改变事件,调用通知订阅者方法 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void txtMain_TextChanged(object sender, EventArgs e) { this.Message = txtMain.Text; NotifyObservers(); } /// <summary> /// 注册订阅者 /// </summary> /// <param name="observer"></param> public void RegisterObserver(IObserver observer) { _observers.Add(observer); } /// <summary> /// 移除订阅者 /// </summary> /// <param name="observer"></param> public void RemoveObserver(IObserver observer) { _observers.Remove(observer); } /// <summary> /// 通知订阅者 /// </summary> public void NotifyObservers() { foreach (IObserver observer in _observers) { observer.Update(Message); } } }
子窗体类(订阅者)的代码以下:设计
public partial class FrmSub1 : Form,IObserver { public FrmSub1(ISubject subject) { InitializeComponent(); //注册 subject.RegisterObserver(this); } //当发布者事件发生时,订阅者须要执行的方法 public void Update(string message,bool isShown) { txtSub.Text = message; } }
上面能够看到FrmMain又依赖了FrmSub1和FrmSub2,其实这是须要另外一个方法Show()。不过为表现出高层不依赖底层,咱们改掉代码,在NotifyObservers(bool isShown)方法中加入对子窗体是否show的判断,从而实现了避免FrmMain依赖FrmSub1,FrmSub2
FrmMain类的代码:code
public partial class FrmMain : Form, ISubject { private string Message { get; set; } private List<IObserver> _observers = new List<IObserver>(); public FrmMain() { InitializeComponent(); } private void FrmMain_Load(object sender, EventArgs e) { //FrmSub1 frmSub1 = new FrmSub1(this); //FrmSub2 frmSub2 = new FrmSub2(this); //frmSub1.Show(); //frmSub2.Show(); //这里咱们使用了方法,摆脱了对子窗体的直接依赖 NotifyObservers(false); } /// <summary> /// 文本框改变事件,调用通知订阅者方法 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void txtMain_TextChanged(object sender, EventArgs e) { this.Message = txtMain.Text; NotifyObservers(true); } /// <summary> /// 注册订阅者 /// </summary> /// <param name="observer"></param> public void RegisterObserver(IObserver observer) { _observers.Add(observer); } /// <summary> /// 移除订阅者 /// </summary> /// <param name="observer"></param> public void RemoveObserver(IObserver observer) { _observers.Remove(observer); } /// <summary> /// 通知订阅者 /// </summary> public void NotifyObservers(bool isShown) { foreach (IObserver observer in _observers) { observer.Update(Message,isShown); } } }
子窗体类的代码:orm
public partial class FrmSub1 : Form,IObserver { public FrmSub1(ISubject subject) { InitializeComponent(); subject.RegisterObserver(this); } //这里对Update作了改变,isShown为true,表示事件触发时子窗体已经显示 public void Update(string message,bool isShown) { if (isShown) { txtSub.Text = message; } else { this.Show(); } } }
[STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); FrmMain frmMain = new FrmMain(); FrmSub1 frmSub1 = new FrmSub1(frmMain); FrmSub2 frmSub2 = new FrmSub2(frmMain); Application.Run(frmMain); }
完整源代码参考:https://gitee.com/Alexander360/ProDotnetDesignPatternFramework45server