C# 之 观察者模式实例 -- 订牛奶

Posted 陈言必行

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# 之 观察者模式实例 -- 订牛奶相关的知识,希望对你有一定的参考价值。

一,观察者模式简介

1.1 观察者模式定义

意图: 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变是,所有依赖于它的对象都能得到通知并自动更新。

适用性:

  1. 当一个对象状态的改变需要改变其他对象, 或实际对象是事先未知的或动态变化的时, 可使用观察者模式。
  2. 当应用中的一些对象对象观察其他对象时,可以使用此模式。订阅列表是动态的,因此订阅者可随时会加入或离开此列表。

1.2 观察者模式结构

  • 发布者:会向其他对象发送值得关注的事件。 事件会在发布者自身状态改变或执行特定行为后发生。 发布者中包含一个允许新订阅者加入和当前订阅者离开列表的订阅构架。

    当新事件发生时, 发送者会遍历订阅列表并调用每个订阅者对象的通知方法。 该方法是在订阅者接口中声明的。

  • 订阅者: 接口声明了通知接口。 在绝大多数情况下, 该接口仅包含一个 update更新方法。 该方法可以拥有多个参数, 使发布者能在更新时传递事件的详细信息。

  • 具体订阅者: 可以执行一些操作来回应发布者的通知。 所有具体订阅者类都实现了同样的接口, 因此发布者不需要与具体类相耦合。

    订阅者通常需要一些上下文信息来正确地处理更新。 因此, 发布者通常会将一些上下文数据作为通知方法的参数进行传递。 发布者也可将自身作为参数进行传递, 使订阅者直接获取所需的数据。

  • 客户端 :会分别创建发布者和订阅者对象, 然后为订阅者注册发布者更新。


二,订牛奶实例

2.1 问题描述

如果你订阅了一份牛奶, 那就不需要再去牛奶店购买牛奶了。 牛奶站 (即应用中的 “发布者”) 会在牛奶到货后 (甚至提前) 直接将牛奶送到你的家中。

牛奶站负责维护订阅者列表, 了解订阅者对哪种牛奶感兴趣。 当订阅者希望停止订阅牛奶时, 他们可随时从该列表中退出。


2.2 实现思路

  1. 声明订阅者接口。 该接口声明一个通知方法。
  2. 声明发布者接口并定义一些接口来在列表中添加和删除订阅对象。
  3. 创建具体发布者类。 每次发布者发生了重要事件时都必须通知所有的订阅者。
  4. 在具体订阅者类中实现通知更新的方法。

2.3 实例代码

using System;
using System.Collections.Generic;

namespace MilkDemo

    // 观察者接口
    public interface IObserver
    
        // 观察者属性 --> 名称之类的 
        string Name  get; set; 

        // 观察者方法 --> 收到通知(被调用)
        void ReceiveMilk(IMilkStation subject);
    
  
    // 订阅用户A
    class ObserverUserA : IObserver
    
        public string Name
        
            get; set;
        

        public ObserverUserA(string name)
        
            this.Name = name;
        

        public void ReceiveMilk(IMilkStation subject)
        
            Console.WriteLine(this.Name + ":我收到了,订阅的牛奶");
            Console.WriteLine(this.Name + "看一下剩余奶站剩余牛奶数量:" + subject.MilkCount);
        
    

    // 订阅用户
    class ObserverUserB : IObserver
    
        public string Name
        
            get; set;
        

        public ObserverUserB(string name)
        
            this.Name = name;
        

        public void ReceiveMilk(IMilkStation subject)
        
            Console.WriteLine(this.Name + ":我收到了,订阅的牛奶");
        
    
    
	// 牛奶站接口
    public interface IMilkStation
    
        int MilkCount  get; set; 

        // 订牛奶 --> 把你添加到送牛奶列表(推送通知)--> 把观察者附在主体上
        void Attach(IObserver observer);

        // 退订牛奶 --> 从移除配送牛奶列表中移除 --> 把观察者从主体上移除
        void Detach(IObserver observer);

        // 配送牛奶 --> 通知观察者
        void Distribution();
    

    /// <summary>
    /// 牛奶配送员
    /// 根据牛奶站订牛奶列表配送牛奶 --> 通知观察者
    /// </summary>
    public class MilkCourier : IMilkStation
           
        // 牛奶站剩余牛奶数量
        public int MilkCount  get; set; 

        // 所有订牛奶的用户 --> 需要被通知的观察者 
        private List<IObserver> observerList = new List<IObserver>();

        public MilkCourier(int milkCount)
        
            this.MilkCount = milkCount;
        

        // 订牛奶方法 -- 添加观察者实现
        public void Attach(IObserver observer)
        
            Console.WriteLine("牛奶站:收到一个用户订奶");
            this.observerList.Add(observer);
        

        // 退订方法 --> 移除观察者实现
        public void Detach(IObserver observer)
        
            this.observerList.Remove(observer);
            Console.WriteLine("牛奶站:收到一个用户退订");
        

        // 在每个订阅者中触发更新。
        public void Distribution()
        
            Console.WriteLine("牛奶站:牛奶配送中...");
            foreach (var observer in observerList)
            
                observer.ReceiveMilk(this);
            
        

        public void SomeLogical()
        
            if (MilkCount > observerList.Count)
            
                Console.WriteLine("奶站剩余牛奶数量: " + this.MilkCount);
                this.MilkCount -= observerList.Count;
                this.Distribution();
                Console.WriteLine("此次配送后剩余数量: " + this.MilkCount);
            
            else
            
                Console.WriteLine("奶站剩余牛奶数量: " + this.MilkCount + ",不足以配送所有订阅用户;");
            
        
    

    class Program
    
        static void Main(string[] args)
        
            // 初始化奶站
            MilkCourier milkCourier = new MilkCourier(10);

            // 初始化用户A,B 并订牛奶
            IObserver observerA = new ObserverUserA("陈言必行");
            milkCourier.Attach(observerA);

            IObserver observerB = new ObserverUserB("Czhenya");
            milkCourier.Attach(observerB);

            // 奶站配送
            milkCourier.SomeLogical();

            Console.WriteLine();
            Console.WriteLine("-------- 模拟过了一段时间 ----------");
            Console.WriteLine();

            // 用户B退订
            milkCourier.Detach(observerB);

            // 奶站配送
            milkCourier.SomeLogical();

            Console.Read();
        
    

运行结果:

以上是关于C# 之 观察者模式实例 -- 订牛奶的主要内容,如果未能解决你的问题,请参考以下文章

《C#零基础入门之百识百例》(七十八)委托事件实例练习3 -- 观察者模式

设计模式之观察者模式

设计模式之观察者模式

观察者模式

观察者模式

微信订阅号的关注和消息推送中的观察者模式