观察者模式深入实践

对于各位看官来说观察者模式都应该不陌生,我也看过一些介绍该模式的文章,但觉得例子中场景都设置的过于简单,未免有些千篇一律。所以,为了更深刻的理解观察者这

个设计模式也就有了下面的这些代码。例子场景的设置是热水壶烧水,水温每次变化时通知注册的观察者,并输出相关水温变化的信息。由调用端触发热水壶的Run()方法来开

启整个烧水和水温变化通知流程。

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

namespace ConsoleApplication1
{
    //本例子实现的是热水壶烧水,水温变化时通知订阅者,订阅者输出水温变化信息
    #region 主题、观察者、热水壶接口定义
    public interface ISubject
    {
        string SubjectName { get; }
        void Attach(IObserver observer);
        void Detach(IObserver observer);
        void Notify();
    }

    public interface IObserver
    {
        void Update();
    }

    public interface IHotWaterPot : ISubject
    {
        /// <summary>
        /// 当前温度
        /// </summary>
        float CurrentTemp { get; }

        /// <summary>
        /// 温度变化
        /// </summary>
        void TempChanged();

        /// <summary>
        /// 开始烧水
        /// </summary>
        void Run();
    }
    #endregion

    #region 主题与观察者抽象类定义,目的是代码重用
    public abstract class Observer : IObserver
    {
        private ISubject _subject = null;

        public Observer(ISubject subject)
        {
            this._subject = subject;
        }

        public ISubject Subject
        {
            get
            {
                return this._subject;
            }
        }
        public abstract void Update();
    }

    public abstract class Subject : ISubject
    {
        private string _subjectName = string.Empty;
        private IList<IObserver> _observers = new List<IObserver>();

        public Subject(string subjectName)
        {
            this._subjectName = subjectName;
        }

        public void Attach(IObserver observer)
        {
            this._observers.Add(observer);
        }

        public void Detach(IObserver observer)
        {
            if (this._observers.Contains(observer))
            {
                this._observers.Remove(observer);
            }
        }

        public string SubjectName
        {
            get { return this._subjectName; }
        }

        public virtual void Notify() {
            foreach (IObserver item in this._observers)
            {
                item.Update();
            }
        }
    }
    #endregion

    #region 热水壶类定义,实现IHotWaterPot接口,具备了烧水的能力,同时本身也是一个Subject
    public class HotWaterPot : Subject, IHotWaterPot {
        private string _potName = string.Empty;
        private float _currentTemp = 0f;
        public HotWaterPot(string potName,float waterTemp)
            : base("热水壶烧水主题")
        {
            this._potName = potName;
            this._currentTemp = waterTemp;
        }

        public float CurrentTemp
        {
            get {
                return this._currentTemp;
            }
        }

        public void TempChanged()
        {
            base.Notify();
        }

        public void Run()
        {
            while(this._currentTemp < 100f) {
                this._currentTemp += 1;
                this.TempChanged();
                Thread.Sleep(1000);
            }

            Console.WriteLine("水烧开了。。。。");
        }
    }
    #endregion

    #region 热水壶观察者类定义
    public class WaterPotObserver : Observer
    {
        private string _name = string.Empty;
        private IHotWaterPot _waterPort = null;

        public WaterPotObserver(ISubject subject, string name)
            : base(subject)
        {
            this._name = name;
        }

        public override void Update()
        {
            this._waterPort = this.Subject as IHotWaterPot;
            if (this._waterPort != null) { 
                Console.WriteLine("Time:{0},观察者:{1},收到主题名为:{2}的消息通知,当前温度是:{3}。。。。"
                    ,DateTime.Now, this._name, this.Subject.SubjectName,this._waterPort.CurrentTemp);
            }
        }
    }
    #endregion


    class Program
    {
        static void Main(string[] args)
        {
            #region 定义subject和observer实例,并进行关联与注册
            ISubject subject = new HotWaterPot("美的点热水壶", 80);
            IObserver observer1 = new WaterPotObserver(subject, "张三");
            IObserver observer2 = new WaterPotObserver(subject, "李四");

            subject.Attach(observer1);
            subject.Attach(observer2);
            #endregion

            //将subject转换为IHotWaterPot类型,并调用Run()方法触发烧水动作
            IHotWaterPot pot = (IHotWaterPot)subject;
            pot.Run();
            Console.ReadKey();
        }
    }
}

 

最终效果图

posted @ 2016-04-02 16:06  玻璃鱼儿  阅读(297)  评论(0编辑  收藏  举报