首页 > 编程知识 正文

设计模式最适合用于发布订阅消息模型,订阅发布者模式的优点

时间:2023-05-06 14:39:38 阅读:178200 作者:3534

订阅发布模型定义了一对多的依赖关系,允许多个读者对象同时接收一个主题对象。 当您的状况发生变化时,此主题对象将通知所有订阅者对象,并且您可以自动更新其状况。

将系统划分为一系列相互协作的类具有以下副作用:必须保持适当对象之间的一致性,这会给维护、扩展和重用带来不便。 如果更改一个对象需要同时更改其他对象,并且不知道需要更改的具体对象数量,则可以使用订阅发布模式。

抽象模型有两个方面,其中一个依赖于另一个。 在这种情况下,订阅发布模型可以将这两个模型封装在独立的对象中,每个对象都可以独立修改和重用。 subscription model所做的工作其实就是解除耦合。 通过使耦合双方依赖抽象而不是具体,使各自的变化不影响对侧的变化。

我们日常编写程序时,经常遇到以下情况。

public void上发生了警告消息(

{

更新接口(;

更新数据库(;

向管理员发送邮件();

..

() ) ) ) )。

发生报警信息时,依次执行界面更新()、数据库更新()、管理员邮件)等操作。 表面上代码写得很好,但实际上这里面有很多问题:

首先,这完全是针对流程开发,不适合大型项目。 第二,代码维护量太大。 想象一下,如果在发出警告后执行10个以上的操作,那将是多么大多么复杂的类。 随着时间的推移,开发者自己可能也不知道如何维护。 第三,可扩展性差。 报警后,如何添加语音提示()功能? 是的。 只能添加到名为报警信息生成()的函数中。 这样做会违反“开放-封闭原则”。 然后,在修改原函数的情况下,在测试时,除了测量新功能外,还进行原功能的回归测试; 对于大型项目,进行回归测试可能需要大约两周的时间。 此外,前提是新功能不影响原始功能,并出现新错误。 那么,如何将产生报警信息的()函数与其他函数解耦呢? 别着急,我来介绍一下今天的主角——订阅发布模式。 请参阅下图:

上述流程是对名为报警信息生成() )的函数的描述。 我们应该做的是解除报警和它需要通知的事件的耦合,使它们之间没有相互依赖关系。 解耦图如下。

事件发生者被抽象化,称为消息发行者,即图中的p。 事件的接收被抽象化,称为消息订阅者,即图中的s。 p和s之间通过S.P,也就是订阅进行连接。 这实现了p和s之间的去耦。 首先,p向指定的读者发送消息。 从头到尾,不知道将消息发送到哪个s,也不关心。 如果s想接收消息,则必须注册订阅程序。 注册成功后,s就可以接收来自S.P的消息了。 从头到尾,s不知道是来自哪个具体p的消息,也不关心。 同样,s也可以对S.P执行取消保留操作,如果取消保留成功,s将无法接收来自指定S.P的消息。 这样,p和s之间的去耦被完美解决。

等等,好像还有一个问题。 从图中可以看出,p和s之间已经完成了谅解结合,但p和S.P,s和S.P之间不是又结合了吗? 其实这个问题很容易解决。 想想前篇的装饰图案是如何解除结合的。 是的,关于接口。 这里也使用接口解决p和S.P、s和S.P之间的解耦,同时使用delegate解决多订阅多发布的机制。

实现代码如下所示。 订阅发放模式涉及p、S.P和s三个内容,因此代码多且长。 各位,请耐心阅读。

首先,必须定义两个接口文件以实现p和S.P、s和S.P之间的去耦

ISubscribe.cs

namespacetjvictor.design pattern.subscribe publish

{

//定义订阅事件

publicdelegatevoidsubscribehandle (stringstr;

//定义订阅接口

公共界面isubscribe

{

eventsubscribehandlesubscribeevent;

() ) ) ) )。

() ) ) ) )。

IPublish

namespacetjvictor.design pattern.subscribe publish

{

//定义释放事件

publicdelegatevoidpublishhandle (stringstr;

//定义释放接口

公共接口I publish

{

event PublishHandle PublishEvent;

voidnotify(stringstr;

() ) ) ) )。

() ) ) ) )。

然后设计订阅吧。 很明显,订户要实现双向去耦,必须继承上面的两个接口。 因此,我不用接口来使用抽象类(类是单一继承的)。

namespacetjvictor.design pattern.subscribe publish

{

公共类子组件

t : ISubscribe, IPublish
    {
        private string _subName;
        public SubPubComponet(string subName)
        {
            this._subName = subName;
            PublishEvent += new PublishHandle(Notify);
        }

        #region ISubscribe Members
        event SubscribeHandle subscribeEvent;
        event SubscribeHandle ISubscribe.SubscribeEvent
        {
            add { subscribeEvent += value; }
            remove { subscribeEvent -= value; }
        }
        #endregion

        #region IPublish Members
        public PublishHandle PublishEvent;

        event PublishHandle IPublish.PublishEvent
        {
            add { PublishEvent += value; }
            remove { PublishEvent -= value; }
        }
        #endregion

        public void Notify(string str)
        {
            if (subscribeEvent != null)
                subscribeEvent.Invoke(string.Format("消息来源{0}:消息内容:{1}", _subName, str));
        }
    }
}

接下来是设计订阅者S。S类中使用了ISubscribe来与S.P进行解耦。代码如下:

namespace TJVictor.DesignPattern.SubscribePublish
{
    public class Subscriber
    {
        private string _subscriberName;

        public Subscriber(string subscriberName)
        {
            this._subscriberName = subscriberName;
        }

        public ISubscribe AddSubscribe { set { value.SubscribeEvent += Show; } }
        public ISubscribe RemoveSubscribe { set { value.SubscribeEvent -= Show; } }

        private void Show(string str)
        {
            Console.WriteLine(string.Format("我是{0},我收到订阅的消息是:{1}", _subscriberName, str));
        }
    }
}

最后是发布者P,继承IPublish来对S.P发布消息通知。

namespace TJVictor.DesignPattern.SubscribePublish
{
    public class Publisher:IPublish
    {
        private string _publisherName;

        public Publisher(string publisherName)
        {
            this._publisherName = publisherName;
        }

        private event PublishHandle PublishEvent;
        event PublishHandle IPublish.PublishEvent
        {
            add { PublishEvent += value; }
            remove { PublishEvent -= value; }
        }

        public void Notify(string str)
        {
            if (PublishEvent != null)
                PublishEvent.Invoke(string.Format("我是{0},我发布{1}消息", _publisherName, str));
        }
    }
}

至此,一个简单的订阅发布模式已经完成了。下面是调用代码及运行结果。调用代码模拟了图2中的订阅发布关系,大家可以从代码,运行结果和示例图三方面对照着看。

#region TJVictor.DesignPattern.SubscribePublish
//新建两个订阅器
SubPubComponet subPubComponet1 = new SubPubComponet("订阅器1");
SubPubComponet subPubComponet2 = new SubPubComponet("订阅器2");
//新建两个发布者
IPublish publisher1 = new Publisher("TJVictor1");
IPublish publisher2 = new Publisher("TJVictor2");
//与订阅器关联
publisher1.PublishEvent += subPubComponet1.PublishEvent;
publisher1.PublishEvent += subPubComponet2.PublishEvent;
publisher2.PublishEvent += subPubComponet2.PublishEvent;
//新建两个订阅者
Subscriber s1 = new Subscriber("订阅人1");
Subscriber s2 = new Subscriber("订阅人2");
//进行订阅
s1.AddSubscribe = subPubComponet1;
s1.AddSubscribe = subPubComponet2;
s2.AddSubscribe = subPubComponet2;
//发布者发布消息
publisher1.Notify("博客1");
publisher2.Notify("博客2");
//发送结束符号
Console.WriteLine("".PadRight(50,'-'));
//s1取消对订阅器2的订阅
s1.RemoveSubscribe = subPubComponet2;
//发布者发布消息
publisher1.Notify("博客1");
publisher2.Notify("博客2");
//发送结束符号
Console.WriteLine("".PadRight(50, '-'));
#endregion

#region Console.ReadLine();
Console.ReadLine();
#endregion

 运行结果图:

 

 

如需转载,请注明本文原创自CSDN TJVictor专栏:http://blog.csdn.net/tjvictor

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。