代码改变世界

观察者模式

2017-06-04 17:21  Dirichlet  阅读(264)  评论(0编辑  收藏  举报

1.  .Net可以很好地支持委托,事件,用事件来实现观察者模式很简洁,最大程度地减少了观察者与Subject之间的耦合。

    class Subject
    {
        public delegate void ChangedEventHandler(object sender, EventArgs args);
        public event ChangedEventHandler Changed;

        public void FireTest()
        {
            if (this.Changed != null)
            {
                this.Changed(this, null);
            }
        }
    }

    class Observer
    {
        public void subject_Changed(object sender, EventArgs args)
        {
            // do something
            //.....
            this.Render();
        }

        private void Render()
        {
            Console.WriteLine("start to reder by the model changes.");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Subject subject = new Subject();
            Observer observer = new Observer();

            subject.Changed += observer.subject_Changed;
            subject.FireTest();
        }
    }

 

 

2. 下面的例子是一个同事用模板实现的观察者模式:

ISubject

    public interface IObserver<in TChange>
    {
        void Update(TChange changes);
    }

 

subject

 public class Subject<TChange> : ISubject<TChange>
    {
        protected ICollection<IObserver<TChange>> Observers = new HashSet<IObserver<TChange>>();

        public void Attach(IObserver<TChange> observer)
        {
            Observers.Add(observer);
        }

        public void Dettach(IObserver<TChange> observer)
        {
            Observers.Remove(observer);
        }

        public void NotifyObservers(TChange changes)
        {
            foreach (IObserver<TChange> observer in Observers)
            {
                observer.Update(changes);
            }
        }
    }

 

IObserver

    public interface IObserver<in TChange>
    {
        void Update(TChange changes);
    }

 

Client program

 public class WeatherData : Subject<Tuple<string, float>>
    {
        private float temperature;

        public float Temperature
        {
            get { return temperature; }
            set
            {
                if (value != temperature)
                {
                    temperature = value;
                    this.NotifyObservers(Tuple.Create("Temperature", value));
                }
            }
        }

        private float pressure;

        public float Pressure
        {
            get { return pressure; }
            set
            {
                if (value != pressure)
                {
                    pressure = value;
                    this.NotifyObservers(Tuple.Create("Pressure", value));
                }
            }
        }

        private float humidity;

        public float Humidity
        {
            get { return humidity; }
            set
            {
                if (value != humidity)
                {
                    humidity = value;
                    this.NotifyObservers(Tuple.Create("Humidity", value));
                }
            }
        }
    }

    public class WeatherDisplay : Label, QiHe.CodeLib.DesignPatterns.IObserver<Tuple<string, float>>
    {
        public void Update(Tuple<string, float> changes)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(() => Display(changes)));
            }
            else
            {
                Display(changes);
            }
        }

        private void Display(Tuple<string, float> data)
        {
            this.Text = string.Format("{0}: {1:F2}", data.Item1, data.Item2);
        }
    }

    public class Test
    {
        [STAThread]
        static void Main()
        {
            WeatherData weatherData = new WeatherData();
            WeatherDisplay dispalay = new WeatherDisplay();
            WeatherDisplay dispalay2 = new WeatherDisplay();
            weatherData.Attach(dispalay);
            weatherData.Attach(dispalay2);

            dispalay2.Top = 50;
            Form form = new Form();
            dispalay.AutoSize = true;
            form.Controls.Add(dispalay);
            form.Controls.Add(dispalay2);

            //new Thread(() => form.ShowDialog()).Start();
            form.Show();

            weatherData.Temperature = 20;
            Console.ReadLine();

            weatherData.Pressure = 80;
            Console.ReadLine();

            weatherData.Humidity = 0.4f;
            Console.ReadLine();
        }
    }