设计模式学习:观察者模式
2017-06-02 14:20
507 查看
观察者模式在开发中是一个普遍应用的设计模式。在我看来,观察者模式主要解决的问题就是解耦,在团队开发中,一个模块可能会有很多不同的功能,而这些功能又有可能被分配到了不同的人来开发。利用观察者模式,可以实现多人的协同开发。每个人只需要按照规则写好自己的功能,并在主题中加入自己的观察者,就可以实现对方法的调用。
传统的观察者模式代码(在开发中没有这么写过):
测试:
而在实际的开发中,都是实现了消息的注册和广播。
下面是一个简单的消息广播,是我写的测试类。正常开发的过程中也是类似于这种
测试:
这里没有实现RemoveListener方法,实现方式和 AddListener相似。这样写方便阅读和使用。
还有一种经常使用的,就是事件访问器,event里提供了add和remove的方法,方便了主体和相关逻辑的分离。
下面上代码:
这个类就相当于观察者模式中的主题类。里面的handle相当于链表,观察者将方法注入进去,在需要的时候,就可以调用这个handle里所有观察者的方法。
下面这个类相当于观察者,向主题注入方法。
测试结果:
这个方法实现了逻辑与主题的分离。
unity里MonoBehaviour不能new(),所以单利要写在Awake或者Start里,否则new不出来。。。
传统的观察者模式代码(在开发中没有这么写过):
/// <summary> /// 主题接口 /// </summary> public interface ISubject { void AddListener(IObserver observer); void RemoveListener(IObserver observer); void Update(); } /// <summary> /// 观察者接口 /// </summary> public interface IObserver { void Excute(); } /// <summary> /// 主题的基类 /// </summary> public class MySubject: ISubject { List<IObserver> list; public MySubject() { list = new System.Collections.Generic.List<IObserver>(); } //添加观察者 public void AddListener(IObserver observer) { list.Add(observer); } //删除观察者 public void RemoveListener(IObserver observer) { list.Remove(observer); } //实现调用所有的观察者中的方法 public void Update() { for (int i = 0; i < list.Count; i++) { list[i].Excute(); } } } /// <summary> /// 具体的主题 /// </summary> public class ConcreteSubject : MySubject { public string food = "苹果"; public string milk = "奶"; } /// <summary> /// 具体的观察者 /// </summary> public class EatObserver : IObserver { ConcreteSubject subject; //实现这个构造器应该是为了获取主题里的数据,并加以利用。其实在我看来并没什么用 public EatObserver(ConcreteSubject subject) { this.subject = subject; } public void Excute() { Debug.Log("Eat:"+subject.food); } } /// <summary> /// 具体的观察者 /// </summary> public class DrinkObserver : IObserver { ConcreteSubject subject; public DrinkObserver(ConcreteSubject subject) { this.subject = subject; } public void Excute() { Debug.Log("Drink:" + subject.milk); } }
测试:
ConcreteSubject subject = new ConcreteSubject(); IObserver eatobserver = new EatObserver(subject); IObserver drinkobserver = new DrinkObserver(subject); subject.AddListener(eatobserver); subject.AddListener(drinkobserver); subject.Update();
而在实际的开发中,都是实现了消息的注册和广播。
下面是一个简单的消息广播,是我写的测试类。正常开发的过程中也是类似于这种
/// <summary> /// 消息类型 /// </summary> public enum Msg { msg_Exit, msg_login, } /// <summary> /// 广播 /// </summary> public class EventHandle { private static EventHandle instance; public static EventHandle Instance { get { if (instance == null) instance = new EventHandle(); return instance; } } //这里只提供了2个委托,正常情况是4个参数就够用了 public delegate void CallBack(); public delegate void CallBack<T>(T t1); //观察者模式中储存观察者的列表 public Dictionary<Msg, Delegate> dic = new Dictionary<Msg, System.Delegate>(); /// <summary> /// 添加消息类型和委托 /// </summary> /// <param name="m"></param> /// <param name="add"></param> public void AddListener(Msg m, CallBack add) { AddingListener(m, add); dic[m] = (CallBack)dic[m] + add; } void AddingListener(Msg m, Delegate add) { if (dic.ContainsKey(m)) { Delegate d = dic[m]; if (dic[m] != null && dic[m].GetType() != add.GetType()) { Debug.Log("Delegate'Type is not Same"); } } else { dic.Add(m, null); } } public class WarnningException : Exception { public WarnningException(string msg) : base(msg) { } } /// <summary> /// 带一个参数的,其他带参数的可以自己补充 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="m"></param> /// <param name="add"></param> public void AddListener<T>(Msg m, CallBack<T> add) { AddingListener(m, add); dic[m] = (CallBack<T>)dic[m] + add; } /// <summary> /// 实现对应消息的委托方法 /// </summary> /// <param name="m"></param> public void Broadcast(Msg m) { if (!dic.ContainsKey(m)) { throw new WarnningException("Dont Have this MsgType!"); } Delegate d; if (dic.TryGetValue(m, out d)) { CallBack callback = d as CallBack; if (callback != null) { callback(); } else { throw new WarnningException("CallBack is Null!"); } } } public void Broadcast<T>(Msg m,T arg1) { if (!dic.ContainsKey(m)) { throw new WarnningException("Dont Have this MsgType!"); } Delegate d; if (dic.TryGetValue(m, out d)) { CallBack<T> callback = d as CallBack<T>; if (callback != null) { callback(arg1); } else { throw new WarnningException("CallBack is Null!"); } } } }
测试:
public class test : MonoBehaviour { public void Start() { //注册消息 EventHandle.Instance.AddListener<string>(Msg.msg_login, Login); EventHandle.Instance.AddListener(Msg.msg_Exit, Exit); //广播消息 EventHandle.Instance.Broadcast<string>(Msg.msg_login,"登录"); EventHandle.Instance.Broadcast(Msg.msg_Exit); } public void Login(string name) { //登录相关的操作 Debug.Log(name); } public void Exit() { Debug.Log("退出"); } }
这里没有实现RemoveListener方法,实现方式和 AddListener相似。这样写方便阅读和使用。
还有一种经常使用的,就是事件访问器,event里提供了add和remove的方法,方便了主体和相关逻辑的分离。
下面上代码:
public class test : MonoBehaviour { public static test instance; void Awake() { instance = this; } public delegate void TouchDelegate(); event TouchDelegate handle=null; public event TouchDelegate TouchEvent { add { handle += value; } remove { handle -= value; } } void Update() { if (handle != null) handle(); } }
这个类就相当于观察者模式中的主题类。里面的handle相当于链表,观察者将方法注入进去,在需要的时候,就可以调用这个handle里所有观察者的方法。
下面这个类相当于观察者,向主题注入方法。
public class ShowTest : MonoBehaviour { void Start() { test.instance.TouchEvent += show; Debug.Log("Awake"); } void show() { Debug.Log("SHOW"); } }
测试结果:
这个方法实现了逻辑与主题的分离。
unity里MonoBehaviour不能new(),所以单利要写在Awake或者Start里,否则new不出来。。。
相关文章推荐
- 观察者设计模式学习!
- 设计模式学习笔记(二十一)——Observer观察者
- HeadFirst 设计模式学习笔记2--观察者模式
- “设计模式”学习之八:备忘录、观察者与状态(行为型)
- head first 设计模式学习随笔(2)----观察者模式
- java 设计模式学习笔记(12) - 观察者模式
- 设计模式学习—Obeserver(观察者)
- 设计模式学习之二观察者模式(Observer)——参与气象观测站的设计
- 步步为营 .NET 设计模式学习笔记 十二、Observer (观察者模式)
- 步步为营 .NET 设计模式学习笔记 十二、Observer (观察者模式)
- 设计模式学习-每日一记(14.观察者模式)
- 学习设计模式之旅 / 观察者模式 (Observers) 推荐
- 学习的设计模式------观察者模式
- 设计模式学习2——观察者模式(Observer)
- java设计模式学习系列之六:Observer, 观察者模式---小例
- 学习设计模式之旅 / 观察者(Observers)委托实现.. 推荐
- 设计模式学习9 -- 观察者模式(Observer)
- 设计模式学习----观察者模式
- 设计模式学习笔记-观察者模式
- 步步为营 .NET 设计模式学习笔记 十二、Observer (观察者模式)