码迷,mamicode.com
首页 > 其他好文 > 详细

模拟项目结构——观察者模式

时间:2014-09-05 14:26:31      阅读:315      评论:0      收藏:0      [点我收藏+]

标签:设计模式   架构分析   架构设计   观察者模式   pubsub   

观察者模式又叫做发布——订阅(Publish/Subscribe)模式。它的概念在我之前的博文中,也多次介绍过。今天,通过一个小Demo,模拟一下项目中使用观察者模式的基本结构。


概念回顾

首先,回顾一下观察者模式的概念。

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主体对象。这个主体对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

             bubuko.com,布布扣

对于这些概念的东西,我们要结合实例来理解,这里我们联想大话设计模式中的例子:

公司中有看球的观察者A,有炒股票的观察者B;而老板和秘书两个通知者,就是两个主题。观察者A和观察者B同时监视着老板的反映。一旦老板有了新的指示,观察者A和观察者B以及所有的其他观察者,都会受到通知。

老板不关心具体谁会收到通知,他只管发通知;而且每个观察者之间也相对独立,他们只关注老板的反映。这就是观察者模式。


项目结构模拟

项目整体结构是这样的:

通过一些设备,实时检测各种类型的数据,新的数据以消息的形式通过Shuttle ESB传输。

Shuttle 服务器接收到消息,它会按照需求要求,对数据进行一定的加工处理,然后将消息注册到消息管理器(注意:这里的消息管理器,就是观察者中的主题)。而每一个显示终端就是一个观察者,当消息注册到消息管理器时,显示终端就会自动更新最新消息,然后在根据要求,进行显示。


这里,大家可以看出来:Shuttle不需要关心有多少个显示终端,它只管接收数据,经过处理后,它会发送给终端。这也就是观察者的好处,将发送和接收以Pub/Sub(发布/订阅)的形式,进行解耦合。

而且,显示终端之间是相互独立的,每个显示终端只是需要接收Shuttle的消息,显示终端彼此之间相互独立。

基本结构如下图:


      bubuko.com,布布扣


代码实现

下面看代码实现:

bubuko.com,布布扣

1、Entity消息

每一种消息被定义为一个实体。如发送给终端的是风报警消息,那么风就定义为一种实体。这样的好处就是做到消息独立,应对变化。

风消息

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Entity
{
    public class WindInfoEntity
    {
        public string id { get; set; }
        public string name{get;set;}
    }
}


雨消息

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Entity
{
    public class RainInfoEntity
    {
        public string id { get; set; }
        public string name { get; set; }
    }
}


2、Subject接口

主题接口,没什么好说的。就是定义添加、移出、通知三个方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Entity;
using Observer;

namespace Subject
{
    /// <summary>
    /// 主题
    /// </summary>
    public interface ISubject
    {
        /// <summary>
        /// 注册观察者
        /// </summary>
        /// <param name="o"></param>
        void registerObserver(IObserver o);
        /// <summary>
        /// 移出观察者
        /// </summary>
        /// <param name="o"></param>
        void removeObserver(IObserver o);
        /// <summary>
        /// 通知观察者
        /// </summary>
        /// <param name="MessageType"></param>
        void notifyObservers(string MessageType);
    }
}


3、主题的实现MessageDataSubject

实现了ISubject接口


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Subject;
using System.Collections;
using Entity;
using Observer;

namespace MessageDataSubject
{
    public class MessageData : ISubject
    {
        public const string WindMessageType = "Wind";
        public const string RainMessageType = "Rain";

        //属性,用于保持数据
        private ArrayList observers;
        IList<WindInfoEntity> WindMessagelist = new List<WindInfoEntity>();
        IList<RainInfoEntity> RainMessagelist = new List<RainInfoEntity>();
        public MessageData()
        {
            observers = new ArrayList();
        }
        public void registerObserver(IObserver o) {
            observers.Add(o);
        }
        public void removeObserver(IObserver o) {
            int i = observers.IndexOf(0);
            if (i > 0) { observers.Remove(o); }
        }
        public void notifyObservers(string pMessageType)
        {
            if (pMessageType == WindMessageType)
            {
                foreach (IObserver o in observers) {
                    o.Update(WindMessagelist);
                }
            }
            if (pMessageType == RainMessageType)
            {
                foreach (IObserver o in observers)
                {
                    o.Update(RainMessagelist);
                }
            }
        }
        public void measurementsChanged(string pMessageType)
        {
            notifyObservers(pMessageType);
        }

        public void setMeasurements(IList<WindInfoEntity> pWindMessagelist)
        {
            this.WindMessagelist = pWindMessagelist;
            measurementsChanged(WindMessageType);
        }
        public void setMeasurements(IList<RainInfoEntity> pRainMessagelist)
        {
            this.RainMessagelist = pRainMessagelist;
            measurementsChanged(RainMessageType);
        }
    }
}


4、CommunicationRouter

定义消息公共访问的方法,因为消息管理器是系统公共访问的,所以需要定义为静态的。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MessageDataSubject;

namespace CommunicationRouter
{
    public class MessageManager
    {
        public static MessageData MessageTransfer { get; set; }
    }
}


5、Globle

提供消息管理器的Get/Set方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MessageDataSubject;
using Subject;
using CommunicationRouter;

namespace Globle
{
    public class GlobleProperty 
    {
        public static MessageData MessageRegister
        {
            get { return MessageManager.MessageTransfer; }
            set { MessageManager.MessageTransfer = value; }
        }
    }
}


6、Observer接口

观察者接口,定义观察者的消息更新方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Entity;

namespace Observer
{
    /// <summary>
    /// 抽象观察者
    /// </summary>
    public interface IObserver
    {
        void Update(IList<WindInfoEntity> winds);
        void Update(IList<RainInfoEntity> rains);
    }
}


7、EquipmentObserver观察者

具体观察者,这里需要将当前的窗体注册到主窗体的消息管理器。然后再实现消息的更新方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Entity;
using Globle;
using MessageDataSubject;
using Observer;
using System.Windows.Threading;

namespace EquipmentObserver
{
    public partial class MainWindow : Window, IObserver
    {
        //定义基站消息管理器
        public static MessageData baseStationMessageData = new MessageData();
        public MainWindow()
        {
            InitializeComponent();
            //将当前窗体注册到主窗体的消息管理器
            GlobleProperty.MessageRegister.registerObserver(this);
        }
        private void Window_Loaded(object sender, RoutedEventArgs e) { }

        public void Update(IList<WindInfoEntity> StateWindlist)
        {
            if (StateWindlist == null || StateWindlist.Count <= 0)
            {
                return;
            }
            foreach (WindInfoEntity wind in StateWindlist)
            {
                Console.WriteLine("********风消息接收:" + new DateTime() + "====" + wind.name);
            }
        }
        public void Update(IList<RainInfoEntity> StateRainlist)
        {
            foreach (RainInfoEntity rain in StateRainlist)
            {
                Console.WriteLine("********雨消息接收:" + new DateTime() + "====" + rain.name);
            }
        }
    }
}


8、客户端

这里是主项目,一般系统登陆后,都应该进入到这里。这里,我们模拟一个发数据的模拟器。每三秒钟发送一次数据。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Entity;
using System.Timers;
using MessageDataSubject;

namespace MainClient
{
    public partial class MainWindow : Window
    {
        //定义消息管理器
        static MessageData _MessageData = new MessageData();

        public MainWindow()
        {
            InitializeComponent();
            Globle.GlobleProperty.MessageRegister = _MessageData;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            //定义一个计时器
            System.Timers.Timer aTimer = new System.Timers.Timer();
            //到达时间的时候执行事件GetAndSendMessages
            aTimer.Elapsed += new ElapsedEventHandler(callAllMessages);
            aTimer.Interval = 3000; //3秒
            aTimer.AutoReset = true; //设置一致执行(true)
            aTimer.Enabled = true; //是否执行System.Timers.Timer.Elapsed事件
        }
        private void callAllMessages(object source, ElapsedEventArgs e)
        {
            Console.WriteLine("************"+new DateTime() +"==MainClient发送消息");
            //调用风推送
            getAndSendWindMessage();
            //调用雨推送
            getAndSendRainMessage();
        }

        /// <summary>
        /// 获取风数据,并推送给客户端
        /// </summary>
        private  void getAndSendWindMessage()
        {
             IList<WindInfoEntity> wind = new List<WindInfoEntity>();
            WindInfoEntity w = new WindInfoEntity();
            w.id = "w_1";
            w.name = "w_风速一级";
            wind.Add(w);

            w.id = "w_2";
            w.name = "w_风速二级";
            wind.Add(w);

            w.id = "w_3";
            w.name = "w_风速三级";
            wind.Add(w);

            w.id = "w_4";
            w.name = "w_风速四级";
            wind.Add(w);

            _MessageData.setMeasurements(wind);
        }

        /// <summary>
        /// 获取雨数据并推送给客户端
        /// </summary>
        private void getAndSendRainMessage()
        {
     IList<RainInfoEntity> rain = new List<RainInfoEntity>();
            RainInfoEntity r = new RainInfoEntity();
            r.id = "r_1";
            r.name = "r_风速一级";
            rain.Add(r);

            r.id = "r_2";
            r.name = "r_风速二级";
            rain.Add(r);

            r.id = "r_3";
            r.name = "r_风速三级";
            rain.Add(r);

            r.id = "r_4";
            r.name = "r_风速四级";
            rain.Add(r);

            _MessageData.setMeasurements(rain);
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            EquipmentObserver.MainWindow mainwin = new EquipmentObserver.MainWindow();
            mainwin.Show();
        }
    }
}


9、结果显示

                                          bubuko.com,布布扣


这里的显示,涉及到了多线程问题,我们不做那么复杂,我们采用控制台输出(如上图)。

我们前端刷新传输数据,占用着主线程;而现在我们要在界面上将信息显示出来,所以我们还需要另一起新线程。这里我们主要是模拟项目中的观察者模式架构模型,这里就不深入阐述多线程了。(感兴趣的朋友,可以在下面留言)


这就是本文要介绍的所有内容。项目中基本的消息传输机制就是这样,项目就是利用观察者模式将发送者与接收者解耦合。

有一些比较灵活的地方。如每一个控件的位置大小,都是根据要求变化的,这时候,就是要在使用一重观察者模式,依照这种思路,再将控件附在窗体上。原理大家应该都懂得,感兴趣的朋友可以自己尝试一下。

模拟项目结构——观察者模式

标签:设计模式   架构分析   架构设计   观察者模式   pubsub   

原文地址:http://blog.csdn.net/liu765023051/article/details/39050799

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!