7

C#面向抽象编程第二讲 - 星仔007

 3 years ago
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.
neoserver,ios ssh client

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)


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK