c#设计模式(3)—— 利用观察者模式模拟推送消息
1、观察者模式概念
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己的行为。
观察者模式实现了表示层和数据逻辑层的分离,并定义了稳定的更新消息传递机制,并抽象了更新接口,使得可以有各种各样不同的表示层,即观察者。
观察者模式在被观察者和观察者之间建立了一个抽象的耦合,被观察者并不知道任何一个具体的观察者,只是保存着抽象观察者的列表,每个具体观察者都符合一个抽象观察者的接口。
2、业务场景
模拟管理系统推送最新讯息给对应用户,采用观察者模式将很好的模拟此类场景,使发布者与订阅者之间实现解耦。
3、实战
3.1 定义实体对象
定义订阅者实体类
namespace SubscriberDesignWithRedis.Model { public class User { /// <summary> /// 用户id /// </summary> public string userId { get; set; } /// <summary> /// 用户名称 /// </summary> public string userName { get; set; } } }
此处List<User> 用于存储订阅者列表
namespace SubscriberDesignWithRedis.Model { [Serializable] public class Information { /// <summary> /// 发布者集合 /// </summary> public List<User> userList{ get; set; } /// <summary> /// 信号 /// </summary> public string signal { get; set; } /// <summary> /// 消息 /// </summary> public string info { get; set; } } }
3.2 发布者
/// <summary> /// 门户发布信息 /// </summary> public class PortalPublish { /// <summary> /// 定义委托方法,充当订阅者接口 /// </summary> /// <param name="obj"></param> public delegate void NotifySubscribeEventHandler(object obj); /// <summary> /// 发布消息内部类 /// </summary> public class PublishInfo { public NotifySubscribeEventHandler notifyEvent; /// <summary> /// 消息实体 /// </summary> public Information Information { get; set; } /// <summary> /// 重载构造器 /// </summary> /// <param name="information">消息实体</param> public PublishInfo(Information information) { this.Information = information; } /// <summary> /// 新增 /// </summary> /// <param name="ob"></param> public void AddSubscribe(NotifySubscribeEventHandler ob){ notifyEvent += ob; } /// <summary> /// 删除 /// </summary> /// <param name="ob"></param> public void RemoveSubscribe(NotifySubscribeEventHandler ob){ notifyEvent -= ob; } /// <summary> /// 更新( 使用lamda表达式 ) /// </summary> public void Update() => notifyEvent?.Invoke(this); } public class PortalPublishInfo : PublishInfo { public PortalPublishInfo(Information information) : base(information) { } } }
3.3 订阅者
namespace SubscriberDesignWithRedis { public class Subscriber { public string Name { get; set; } public Subscriber(string name) { this.Name = name; } /// <summary> /// 接收 /// </summary> /// <param name="obj"></param> public void Recevie(object obj) { PortalPublish.PortalPublishInfo portalPublishInfo = obj as PortalPublish.PortalPublishInfo; if(portalPublishInfo != null) { Console.WriteLine("Notified {0} of {1}'s " + "Info is :{2}", Name,
portalPublishInfo.Information.signal, portalPublishInfo.Information.info); } } } }
3.4 测试类
namespace SubscriberDesignWithRedis { class Program { static void Main(string[] args) { //模拟订阅者的集合 List<User> userList = new List<User>() { new User() { userId = "1", userName = "ozil" }, new User() { userId = "2",userName = "Alexis"} }; //定义发布数据 Information information = new Information() { signal = "Publish Info", info = "this is a new information for each client", userList = userList }; PortalPublishInfo portalPublish = new PortalPublishInfo(information); Console.WriteLine("添加订阅者"); //循环订阅者列表,将消息发送给具体订阅者 foreach (User user in userList) { Subscriber client = new Subscriber(user.userName); portalPublish.AddSubscribe(new NotifySubscribeEventHandler(client.Recevie)); } //执行事件 portalPublish.Update(); Console.WriteLine("--------------------------------------------"); Console.WriteLine("移除订阅者"); foreach (User user in userList) { Subscriber client = new Subscriber(user.userName); portalPublish.RemoveSubscribe(new NotifySubscribeEventHandler(client.Recevie)); } //执行事件 portalPublish.Update(); Console.ReadLine(); } } }
4、运行结果