

C#面向抽象编程第二讲 - 星仔007
source link: https://www.cnblogs.com/morec/p/16138268.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C#面向抽象编程第二讲
抽象编程怎么说呢,以观察者模式为例:
观察者模式有两个对象,一个是观察者,一个是可观察者(字面翻译很别扭observable),消息发布者(提供者)。
第一层如下,三个对象A、B、C分别有一个接收消息的方法,还有一个存储数据的字段,X就是发布消息的对象,它通过setdata方法设置自己的字段data,然后通知abc,abc如愿以偿地拿到了通知,完美!
internal class A { public int Data; public void Update(int data) { this.Data = data; } } internal class B { public int Count; public void Notify(int data) { this.Count = data; } } internal class C { public int N; public void Set(int data) { this.N = data; } } internal class X { private int data; public A instanceA; public B instanceB; public C instanceC; public void SetData(int data) { this.data = data; instanceA.Update(data); instanceB.Notify(data); instanceC.Set(data); } } using ObserverOne; A a = new A(); B b = new B(); C c = new C(); Console.WriteLine("订阅前................."); Console.WriteLine($"a.Data = {a.Data}"); Console.WriteLine($"b.Count = {b.Count}"); Console.WriteLine($"c.N = {c.N}"); X x =new X(); x.instanceA = a; x.instanceB = b; x.instanceC = c; x.SetData(10); Console.WriteLine("X发布data=10, 订阅后................."); Console.WriteLine($"a.Data = {a.Data}"); Console.WriteLine($"b.Count = {b.Count}"); Console.WriteLine($"c.N = {c.N}");
再想一想,这好像不够灵活,订阅者是死的,那改进一下:
internal interface IUpdatebleObject { int Data { get; } void Update(int newData); } internal class A : IUpdatebleObject { public int Data => data; private int data; public void Update(int newData) { this.data = newData; } } internal class B : IUpdatebleObject { public int Data => data; private int data; public void Update(int newData) { this.data = newData; } } internal class C : IUpdatebleObject { public int Data => data; private int data; public void Update(int newData) { this.data = newData; } } internal class X { private IUpdatebleObject[] updates=new IUpdatebleObject[3]; public IUpdatebleObject this[int index] { set { updates[index] = value; } } private int data; public void Update(int newData) { this.data = newData; foreach (var update in updates) { update.Update(newData); } } } using ObserverTwo; X x = new X(); IUpdatebleObject a = new A(); IUpdatebleObject b = new B(); IUpdatebleObject c = new C(); Console.WriteLine("订阅前................."); Console.WriteLine($"a.Data = {a.Data}"); Console.WriteLine($"b.Data = {b.Data}"); Console.WriteLine($"c.Data = {c.Data}"); x[0] = a; x[1] = b; x[2] = c; x.Update(10); Console.WriteLine("X发布data=10, 订阅后................."); Console.WriteLine($"a.Data = {a.Data}"); Console.WriteLine($"b.Data = {b.Data}"); Console.WriteLine($"c.Data = {c.Data}");
虽然写到这个例子已经很了不起了,但是对于有想法的来说还是可以继续改进,要不然怎么常挂嘴边说面对抽象编程呢,那就继续改进了:
/// <summary> /// 观察者 /// </summary> /// <typeparam name="T"></typeparam> internal interface IObserver<T> { void Update(SubjectBase<T> subject); }
/// <summary> /// 可观察者(发出通知的对象) /// </summary> /// <typeparam name="T"></typeparam> internal abstract class SubjectBase<T> { protected IList<IObserver<T>> observers = new List<IObserver<T>>(); protected T state; public virtual T State => state; public static SubjectBase<T> operator +(SubjectBase<T> subject,IObserver<T> observer) { subject.observers.Add(observer); return subject; } public static SubjectBase<T> operator -(SubjectBase<T> subject,IObserver<T> observer) { subject.observers.Remove(observer); return subject; } public virtual void Notify() { foreach (var observer in observers) { observer.Update(this); } } public virtual void Update(T state) { this.state = state; Notify(); } }
internal class Observer<T> : IObserver<T> { public T State; public void Update(SubjectBase<T> subject) { this.State = subject.State; } }
internal class Subject<T>:SubjectBase<T> { }
到这里基本上可以说是把骨架搭起来了,这些可以称之为底层的代码。实现代码如下:
internal class TestObserver { public void TestMulticst() { SubjectBase<int> subject = new Subject<int>(); Observer<int> observer1 = new Observer<int>(); observer1.State = 10; Observer<int> observer2 = new Observer<int>(); observer2.State = 20; subject += observer1; subject += observer2; subject.Update(1); Console.WriteLine($"observer1.State={observer1.State} observer2.State={observer2.State}"); subject -= observer1; subject.Update(100); Console.WriteLine($"update state = 100, observer1.State={observer1.State} observer2.State={observer2.State}"); } public void TestMultiSubject() { SubjectBase<string> subject1 = new Subject<string>(); SubjectBase<string> subject2 = new Subject<string>(); Observer<string> observer1 = new Observer<string>(); observer1.State = "运动"; Console.WriteLine($"observer1.State={observer1.State}"); subject1 += observer1; subject2 += observer1; subject1.Update("看电影"); Console.WriteLine($"observer1.State={observer1.State}"); subject2.Update("喝茶"); Console.WriteLine($"observer1.State={observer1.State}"); subject1 -= observer1; subject2 -= observer1; observer1.State = "休息"; subject1 -= observer1; subject2 -= observer1; Console.WriteLine($"observer1.State={observer1.State}"); } }
using ObserverThree; //new TestObserver().TestMulticst(); new TestObserver().TestMultiSubject();
到这里基本上就完成了任务,也就可以结束了。但是,学习需要深度也需要宽度,所以观察者模式在C#可以通过事件来实现一样的效果。下面就看下上面写这么多的代码用事件怎么写呢,这里的实例稍作变化,实现改变名字通知观察者,这里观察者就是控制台了,打印通知:
internal class UserEventArgs:EventArgs { private string name; public string Name => name; public UserEventArgs(string name) { this.name = name; } }
internal class User { public event EventHandler<UserEventArgs> NameChanged; private string name; public string Name { get { return name; } set { name = value; NameChanged?.Invoke(this, new UserEventArgs(value)); } } }
using ObserverFour; User user = new User(); user.NameChanged += OnNameChanged; user.Name = "joe"; void OnNameChanged(object sender, UserEventArgs args) { Console.WriteLine($"{args.Name} Changed "); }
再放一个麻烦一点的例子,字典新增的通知(监听)事件:
internal class DictionaryEventArgs<TKey,TValue> : EventArgs { private TKey key; private TValue value; public DictionaryEventArgs(TKey key,TValue value) { this.key = key; this.value = value; } public TKey Key => key; public TValue Value => value; }
internal interface IObserverableDictionary<TKey,TValue>:IDictionary<TKey, TValue> { EventHandler<DictionaryEventArgs<TKey,TValue>> NewItemAdded { get; set; } }
internal class ObserverableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IObserverableDictionary<TKey, TValue> { protected EventHandler<DictionaryEventArgs<TKey, TValue>> newItemAdded; public EventHandler<DictionaryEventArgs<TKey, TValue>> NewItemAdded { get => newItemAdded;set=> newItemAdded = value;} public new void Add(TKey key,TValue value) { base.Add(key, value); if(NewItemAdded != null) NewItemAdded(this, new DictionaryEventArgs<TKey, TValue>(key, value)); } }
using ObserverFive; string key = "hello"; string value = "world"; IObserverableDictionary<string,string> dictionary = new ObserverableDictionary<string,string>(); dictionary.NewItemAdded += Validate; dictionary.Add(key, value); void Validate(object sender, DictionaryEventArgs<string,string> args) { Console.WriteLine($"{args.Key} {args.Value}"); }
事件说完了!再回头看看观察者设计模式。
微软已经很重视观察者模式这个设计,把IObserver、IObservable集成到runtime里面去了,也就是基类库里面。aspnetcore框架也有用到这个,比如日志模块。所以感觉有必要了解一下,放个小例子作为结束:
internal class Message { public string Notify { get; set; } }
internal class Teacher : IObservable<Message> { private readonly List<IObserver<Message>> _observers; public Teacher() { _observers = new List<IObserver<Message>>(); } public IDisposable Subscribe(IObserver<Message> observer) { _observers.Add(observer); return new Unsubscribe(observer, _observers); } public void SendMessage(string message) { foreach (var observer in _observers) { observer.OnNext(new Message() { Notify = "message" }); } } public void OnCompleted() { foreach (var observer in _observers) { observer.OnCompleted(); } _observers.Clear(); } } internal class Unsubscribe:IDisposable { private readonly IObserver<Message> _observer; private readonly List<IObserver<Message>> _observers; public Unsubscribe(IObserver<Message> observer, List<IObserver<Message>> observers) { this._observers = observers; this._observer = observer; } public void Dispose() { if(_observers.Contains(_observer)) _observers.Remove(_observer); } }
internal abstract class Student : IObserver<Message> { private string name; public Student(string name) { this.name = name; } private IDisposable _unsubscribe; public virtual void OnCompleted() { Console.WriteLine("放学了..."); } public virtual void OnError(Exception error) { Console.WriteLine("生病了..."); } public virtual void OnNext(Message value) { Console.WriteLine($"大家好: 我是 {name} -_- "); Console.WriteLine($"老师说:{value.Notify}"); } public virtual void Subscribe(IObservable<Message> obserable) { if (obserable != null) _unsubscribe = obserable.Subscribe(this); } }
internal class StudentZhang : Student { public StudentZhang(string name) : base(name) { } } internal class StudentLi : Student { public StudentLi(string name) : base(name) { } }
using ObserverSeven; Teacher teacher = new Teacher(); teacher.Subscribe(new StudentLi("李逵")); teacher.Subscribe(new StudentZhang("张麻子")); teacher.SendMessage("明天放假"); teacher.OnCompleted(); //这里学生是多个,也定义可以多个老师,实现多对多关系
示例代码:
Recommend
-
21
作者:svenzeng,腾讯 PCG 前端开发工程师 面向抽象编程,是构建一个大型系统非常重要的参考原则。 但对于许多前端同学来说,对面向抽象编程的理解说不上很深刻。大部分同学的习惯是 拿到需求单和设计稿之后就开始编写...
-
8
面向对象编程核心是多态!不是抽象哦 | by Sohee Kim 运行良好的软件和运行正常的软件之间是有区别的。仅考虑其行为,构建有效的软件是一项工作完成了一半。软件工程师应该...
-
8
Python函数式编程系列007:惰性求值本系列文章一些重要的函数、方法、类我都实现的一遍,你可以在
-
5
netcore后台任务注意事项 开局一张图,故事慢慢编!这是一个后台任务打印时间的德莫,代码...
-
10
微服务简单实现最终一致性 有花时间去研究masstransit的saga,英文水平不过关,始终无法实...
-
14
aspnetcore6.0源代码编译调试 虽然编译源码折腾了几个时...
-
14
高并发解决方案orleans实践
-
4
docker下netcore内存dump 一般开发阶段可以通过visualstu...
-
7
aspnetcore中aop的实现 aaspnetcore开发框架中实现aop不...
-
9
面向接口编程实践之aspnetcoreapi的抽象 最为一名越过菜...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK