场景

一个对象A,希望它的某些状态在发生改变时通知到B(或C、D),
常见的做法是在A中定义一个事件(或直接用委托),当状态改变时A去触发这个事件。而B直接订阅这个事件

这种设计有点问题
B由于要订阅A的事件,所以B得完全引用A,其实有时候没必要,因为我只关心A的状态变化而已
状态变更通知这种场景很多,有没有更通用的方式呢?

解决思路

有个谁说的碰到问题加个中间层就解决了,如果解决不了就再加一层

A和B都引用ChangeToken,
B向ChangeToken注册一个委托说:将来你有变化时回调我这个委托
当A的状态变化时会调用ChangeToken的一个方法,这个方法内部就会去触发执行B之前塞进去的委托
此时比如有组件C、D、E..都关心A的状态变化,也可以引用ChangeToken,并向其注册自己的委托
这样ChangeToken可以作为一个通用组件,在很多需要更改通知是场景中使用,如:asp.net core的配置系统、终结点路由、 ....

实现

微软定义了一个IChangeToken
HasChanged:表示当前这个ChangeToken是否变化过了
ActiveChangeCallbacks:当 A触发ChangeToken发生变化时是否主动回调B塞进来的委托
RegisterChangeCallback(Action<object> callback, object state):提供一个方法,允许调用方塞入委托,B就是调用这个方法向ChangeToken塞入委托的。有一种情况是B希望在塞入委托的同时附带一个状态对象,将来委托被执行时这个状态对象作为执行委托的参数

CancellationChangeToken是一个用的比较多的实现类,它包含一个CancellationToken属性,这个属性是通过构造函数来初始化的(CancellationTokenSource、CancellationToken自行查询相关资料),
简化的源码如下:

 1 public class CancellationChangeToken : IChangeToken
 2 {
 3         public CancellationChangeToken(CancellationToken cancellationToken)
 4         {
 5             Token = cancellationToken;
 6         }
 7
 8         public bool ActiveChangeCallbacks { get; private set; } = true;
 9
10         public bool HasChanged => Token.IsCancellationRequested;
11
12         private CancellationToken Token { get; }
13
14         public IDisposable RegisterChangeCallback(Action<object> callback, object state)
15         {
16               return Token.Register(callback, state);
17         }
18     }

因为CancellationToken天然的已经现了IChangeToken,因此CancellationChangeToken只是对CancellationToken的包装。那为啥不直接让CancellationToken实现IChangeToken呢?我感觉是设计意图不同,CancellationToken设计时主要是考虑应用在取消异步操作这件事上的,只是碰巧取消异步操作与更改通知设计思路是相似的,所以才出现CancellationChangeToken

其它的实现类没去研究过,但是只要你对这种设计思路理解了,碰到其它实现类应该看看就明白了

例子

下面我们使用CancellationChangeToken来完成上面的A、B类,A类状态变化时 通知到B类(其实就是执行B类忘ChangeToken中塞入的委托),完整源码如下:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Console.OutputEncoding = Encoding.UTF8;
 6             CancellationTokenSource cts = new CancellationTokenSource();
 7             CancellationChangeToken cct = new CancellationChangeToken(cts.Token);
 8             var a = new A(cts);
 9             var b = new B(cct);
10             Console.ReadKey();
11         }
12     }
13
14     public class A
15     {
16         CancellationTokenSource _cts;
17         public A(CancellationTokenSource cts)
18         {
19             this._cts = cts;
20             Task.Run(() =>
21             {
22                 Task.Delay(2000).Wait();
23                 Console.WriteLine("模拟触发更改通知");
24                 _cts.Cancel();
25             });
26         }
27     }
28     public class B
29     {
30         public B(CancellationChangeToken cct) {
31             object testState = 1;
32             cct.RegisterChangeCallback(obj => {
33                 //将来cct检测到变化时此委托会被执行
34                 //obj是注册委托是传递进来的参数,就是这里的testState
35                 Console.WriteLine($"状态变化了,状态值{obj}");
36             }, testState);
37         }
38     }

上面只是演示IChangeToken的思路,asp.net core中源码的应用时通常是在A中提供一个返回IChangeToken的方法

无限监控与ChangeToken.OnChange

上面的方式只能变更通知一次,下面可以永远监控

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Console.OutputEncoding = Encoding.UTF8;
 6             var a = new A();
 7             //实现无限监控状态变化。OnChange有两个委托类型的参数,我们分别称为委托1和委托2
 8             ChangeToken.OnChange(() => a.CreateChangeToken(), () => Console.WriteLine("a状态变化了"));
 9             Console.ReadKey();
10         }
11     }
12
13     public class A
14     {
15         CancellationTokenSource _cts;
16         public A()
17         {
18             Task.Run(() =>
19             {
20                 while (true)
21                 {
22                     Task.Delay(2000).Wait();
23                     Console.WriteLine("模拟两秒一次触发一次状态修改通知");
24                     this._cts.Cancel();
25                 }
26             });
27         }
28
29         public IChangeToken CreateChangeToken() {
30             _cts = new CancellationTokenSource();
31             return new CancellationChangeToken(_cts.Token);
32         }
33     }

重点是这句:ChangeToken.OnChange(() => a.CreateChangeToken(), () => Console.WriteLine("a状态变化了"));
OnChange有两个委托类型的参数,我们分别称为委托1和委托2,当a的状态变化后会执行委托2,之后会执行委托1,当a状态又变化时又会执行委托2,之后执行委托1,如此往复实现无限监控

这是今天学习的内容,可能理解得不是很准确,仅供参考...

.net core 常见设计模式-IChangeToken相关推荐

  1. java面试常见设计模式

    java面试常见设计模式 看这里,动画描述很好 创建型模式 工厂方法模式 目的 结构 场景 优缺点 示例代码 button factory Demo.java: 客户端代码 抽象工厂模式 目的 结构 ...

  2. JavaScript 中常见设计模式整理

    开发中,我们或多或少地接触了设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式.本文意在梳理常见设计模式的特点,从而对它们有比较清晰的认知. JavaScript 中常见设计模 ...

  3. Android常见设计模式——代理模式(Proxy Pattern)(二)

    文章目录 1. 前言 2. 远程代理(Remote Proxy) 3. 后记 1. 前言 在上篇Android常见设计模式--代理模式(Proxy Pattern)中基本上知道了什么是代理模式,以及对 ...

  4. ☀️一张思维图带大家了解Java常见设计模式☀️《❤️记得收藏❤️》

    ☀️一张思维图带大家了解Java常见设计模式☀️<❤️记得收藏❤️> 目录

  5. PHP 常见设计模式——工厂模式

    最近参加了几次面试,对于应用常见的几种设计模式问题,深有感触.为加强自身理解,同时也希望能给一些初级开发者一定的参考学习,决定开始就PHP常见的设计模式写下几篇博文,工作原因,会不定期更新,感谢您的耐 ...

  6. Java 10种常见设计模式UML图

    Java 10种常见设计模式UML图 简单工厂模式(不属于23种设计模式) 工厂方法模式 单例 模式(静态内部类方式 IODH) 适配器模式 装饰者模式 门面模式 代理模式(静态代理) 观察者模式 策 ...

  7. 5 修改request对象变量_【总结】前端5大常见设计模式,代码一看你就懂!

    前言 今天主要介绍一下我们平常会经常用到的设计模式,设计模式总的来说有23种,而设计模式在前端中又该怎么运用呢,接下来主要对比较前端中常见的设计模式做一个介绍. 设计模式的定义 设计模式是在面向对象软 ...

  8. 如何理解这6种常见设计模式?

    简介:设计模式能够帮助我们优化代码结构,让代码更优雅灵活.有哪些常见的设计模式?如何合理运用?本文分享作者对工厂模式.单例模式.装饰模式.策略模式.代理模式和观察者模式的理解,介绍每种模式的模式结构. ...

  9. Golang 常见设计模式之选项模式

    熟悉 Python 开发的同学都知道,Python 有默认参数的存在,使得我们在实例化一个对象的时候,可以根据需要来选择性的覆盖某些默认参数,以此来决定如何实例化对象.当一个对象有多个默认参数时,这个 ...

最新文章

  1. 能够附加图片的标签控件iOS项目源码
  2. 双网口相机用序列号打开
  3. SpannableString
  4. 接口与继承 课后实践
  5. switch与if效率实例解析·5年以下编程经验必看【C#】
  6. Spring 注入集合的成员变量属性
  7. websocket实现多屏互动_纸笔互动课堂应用场景到底有些什么呢?
  8. 【微信小程序】目前最全的《Java面试题及解析》
  9. Bootstrap 警告框的外观
  10. Notepad++的SQL格式化插件
  11. matlab 图例自定义,matlab实现自定义曲线图以及图例
  12. 华为2020秋招笔试试题
  13. python实现输出日历_python实现输出日历
  14. 植物DNA甲基化专题 | nature:油棕Karma转座子表观遗传重要发现
  15. UOS主动安全防护计划(UAPP)正式发布,共建信创基础软件平台安全底座
  16. mysql数据长度过长,1406 - Data too long for column ‘express_company‘ at row 1
  17. python有什么颜色_Python中常见颜色记录
  18. Excel进度条设置百分比解决
  19. Vue install 报错 code EINTEGRITY
  20. error: ‘uint8_t’,‘uint16_t’ ,‘uint32_t’ does not name a type

热门文章

  1. Objective-C 2.0 with Cocoa Foundation--- 4,继承
  2. WordPress 三个必须的安全措施
  3. Linux应用程序设置进程调度策略
  4. Linux LiveCD:从CD光盘运行Linux
  5. 【AI视野·今日NLP 自然语言处理论文速览 第八期】Wed, 16 Jun 2021
  6. 【python】numpy数组的维度增减方法
  7. Java—一篇读懂java集合(Collection/Map)及Lambda表达式
  8. 【Linux】shell命令学习之find
  9. 【设计模式】设计模式C++编程实现之观察者模式(ObserverPattern)
  10. 9203精英挑战赛注意事宜 一