当前位置:网站首页>C# 之 观察者模式实例 -- 订牛奶
C# 之 观察者模式实例 -- 订牛奶
2022-07-28 17:06:00 【陈言必行】
一,观察者模式简介
1.1 观察者模式定义
意图: 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变是,所有依赖于它的对象都能得到通知并自动更新。
适用性:
- 当一个对象状态的改变需要改变其他对象, 或实际对象是事先未知的或动态变化的时, 可使用观察者模式。
- 当应用中的一些对象对象观察其他对象时,可以使用此模式。订阅列表是动态的,因此订阅者可随时会加入或离开此列表。
1.2 观察者模式结构
发布者:会向其他对象发送值得关注的事件。 事件会在发布者自身状态改变或执行特定行为后发生。 发布者中包含一个允许新订阅者加入和当前订阅者离开列表的订阅构架。
当新事件发生时, 发送者会遍历订阅列表并调用每个订阅者对象的通知方法。 该方法是在订阅者接口中声明的。
订阅者: 接口声明了通知接口。 在绝大多数情况下, 该接口仅包含一个 update更新方法。 该方法可以拥有多个参数, 使发布者能在更新时传递事件的详细信息。
具体订阅者: 可以执行一些操作来回应发布者的通知。 所有具体订阅者类都实现了同样的接口, 因此发布者不需要与具体类相耦合。
订阅者通常需要一些上下文信息来正确地处理更新。 因此, 发布者通常会将一些上下文数据作为通知方法的参数进行传递。 发布者也可将自身作为参数进行传递, 使订阅者直接获取所需的数据。
客户端 :会分别创建发布者和订阅者对象, 然后为订阅者注册发布者更新。
二,订牛奶实例
2.1 问题描述
如果你订阅了一份牛奶, 那就不需要再去牛奶店购买牛奶了。 牛奶站 (即应用中的 “发布者”) 会在牛奶到货后 (甚至提前) 直接将牛奶送到你的家中。
牛奶站负责维护订阅者列表, 了解订阅者对哪种牛奶感兴趣。 当订阅者希望停止订阅牛奶时, 他们可随时从该列表中退出。
2.2 实现思路
- 声明订阅者接口。 该接口声明一个通知方法。
- 声明发布者接口并定义一些接口来在列表中添加和删除订阅对象。
- 创建具体发布者类。 每次发布者发生了重要事件时都必须通知所有的订阅者。
- 在具体订阅者类中实现通知更新的方法。
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();
}
}
}
运行结果:
边栏推荐
- What skills do you need to master when learning software testing zero foundation?
- Docker builds MySQL master-slave replication
- 深圳线下报名|StarRocks on AWS:如何对实时数仓进行极速统一分析
- Syntax error: non declaration statement outside function bodygo and syntax error: unexpected {, expect
- #夏日挑战赛#【FFH】JS自定义组件:DIY一个随点随用的键盘!(一)
- SQL Server stuff and for XML path
- Golang is packaged and released to various platforms
- UE5 GAS 学习笔记 1.9 技能系统全局类(AbilitySystemGlobals)
- VSC writes go, expected 'package' appears, found 'EOF‘
- 1.1、稀疏数组
猜你喜欢

Live broadcast starrocks technology insider: low base global dictionary optimization

Brief introduction: basic principle of srv6

1.1. Sparse array

Random talk on GIS data (VI) - projection coordinate system

MYSQL入门与进阶(一)

ERROR 2003 (HY000) Can‘t connect to MySQL server on ‘localhost3306‘ (10061)解决办法

Noise of creative coding

Six countries in Europe and the United States launched an express line product to optimize the "end-to-end" performance service on the 5th

Wired: who owns the art of the future? Openai allows dall-e users to commercialize their works. At present

EasyNLP中文文图生成模型带你秒变艺术家
随机推荐
What is the employment prospect of software testing?
Introduction to main parameters of antenna
leetcode 二叉树类
MYSQL入门与进阶(三)
Introduction and advanced level of MySQL (8)
MYSQL入门与进阶(六)
What is the employment prospect of software testing?
Mongodb create index
Brief introduction: basic principle of srv6
Random talk on GIS data (VI) - projection coordinate system
1.2、队列
Go's walk library reports an error
How does Xiaobai learn software testing with zero foundation?
2022.7.26 constructor, interview: the role of new, deep copy and shallow copy
UE5 GAS 学习笔记 1.5 Gameplay Effects游戏效果
Error 2003 (HY000) can't connect to MySQL server on 'localhost3306' (10061) solution
LeetCode_343_整数拆分
Introduction and advanced level of MySQL (6)
ERROR 2003 (HY000) Can‘t connect to MySQL server on ‘localhost3306‘ (10061)解决办法
十进制转二进制进阶版(可转化负数以及边界值)