• 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)

  • 相关阅读:
    Opencv在mac系统的安装与试用
    VINS 估计器之检查视差
    C语言——第零次作业
    C语言博客05指针
    循环结构
    C语言博客作业数组
    函数3
    C博客作业01分支、顺序结构
    group by的查询
    layui多张图片上传最多9张(新增和修改时的显示问题)
  • 原文地址:https://www.cnblogs.com/morec/p/16138268.html
Copyright © 2020-2023  润新知