C#面向抽象编程第二讲

博客 动态
0 219
羽尘
羽尘 2022-04-12 23:57:53
悬赏:0 积分 收藏

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();//这里学生是多个,也定义可以多个老师,实现多对多关系

 

示例代码:

exercise/发布订阅And出版预定_EventBus_Observer/Observer/Observer at master · liuzhixin405/exercise (github.com)

posted @ 2022-04-12 23:37 星仔007 阅读(0) 评论(0) 编辑 收藏 举报
回帖
    羽尘

    羽尘 (王者 段位)

    2335 积分 (2)粉丝 (11)源码

     

    温馨提示

    亦奇源码

    最新会员