C#面向抽象编程第二讲

2022年5月22日10:07:20

抽象编程怎么说呢,以观察者模式为例:

观察者模式有两个对象,一个是观察者,一个是可观察者(字面翻译很别扭observable),消息发布者(提供者)。

第一层如下,三个对象A、B、C分别有一个接收消息的方法,还有一个存储数据的字段,X就是发布消息的对象,它通过setdata方法设置自己的字段data,然后通知abc,abc如愿以偿地拿到了通知,完美!

internalclass A
    {publicint Data;publicvoid Update(int data)
        {this.Data = data;
        }
    }internalclass B
    {publicint Count;publicvoid Notify(int data)
        {this.Count = data;
        }
    }internalclass C
    {publicint N;publicvoid Set(int data)
        {this.N = data;
        }
    }internalclass X
    {privateint data;public A instanceA;public B instanceB;public C instanceC;publicvoid 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}");

再想一想,这好像不够灵活,订阅者是死的,那改进一下:

internalinterface IUpdatebleObject
    {int Data {get; }void Update(int newData);
    }internalclass A : IUpdatebleObject
    {publicint Data => data;privateint data;publicvoid Update(int newData)
        {this.data = newData;
        }
    }internalclass B : IUpdatebleObject
    {publicint Data => data;privateint data;publicvoid Update(int newData)
        {this.data = newData;
        }
    }internalclass C : IUpdatebleObject
    {publicint Data => data;privateint data;publicvoid Update(int newData)
        {this.data = newData;
        }
    }internalclass X
    {private IUpdatebleObject[] updates=new IUpdatebleObject[3];public IUpdatebleObjectthis[int index]
        {set { updates[index] = value; }
        }privateint data;publicvoid Update(int newData)
        {this.data = newData;foreach (var updatein 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>internalinterface IObserver<T>
    {void Update(SubjectBase<T> subject);
    }
///<summary>/// 可观察者(发出通知的对象)///</summary>///<typeparam name="T"></typeparam>internalabstractclass SubjectBase<T>
    {protected IList<IObserver<T>> observers =new List<IObserver<T>>();protected T state;publicvirtual T State => state;publicstatic SubjectBase<T>operator +(SubjectBase<T> subject,IObserver<T> observer)
        {
            subject.observers.Add(observer);return subject;
        }publicstatic SubjectBase<T>operator -(SubjectBase<T> subject,IObserver<T> observer)
        {
            subject.observers.Remove(observer);return subject;
        }publicvirtualvoid Notify()
        {foreach (var observerin observers)
            {
                observer.Update(this);
            }
        }publicvirtualvoid Update(T state)
        {this.state = state;
            Notify();
        }
    }
internalclass Observer<T> : IObserver<T>
    {public T State;publicvoid Update(SubjectBase<T> subject)
        {this.State = subject.State;
        }
    }
internalclass Subject<T>:SubjectBase<T>
    {
    }

到这里基本上可以说是把骨架搭起来了,这些可以称之为底层的代码。实现代码如下:

internalclass TestObserver
    {publicvoid 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}");
        }publicvoid 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#可以通过事件来实现一样的效果。下面就看下上面写这么多的代码用事件怎么写呢,这里的实例稍作变化,实现改变名字通知观察者,这里观察者就是控制台了,打印通知:

internalclass UserEventArgs:EventArgs
    {privatestring name;publicstring Name => name;public UserEventArgs(string name)
        {this.name = name;
        }

    }
internalclass User
    {publicevent EventHandler<UserEventArgs> NameChanged;privatestring name;publicstring 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");
}

再放一个麻烦一点的例子,字典新增的通知(监听)事件:

internalclass 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;
    }
internalinterface IObserverableDictionary<TKey,TValue>:IDictionary<TKey, TValue>
    {
        EventHandler<DictionaryEventArgs<TKey,TValue>> NewItemAdded {get;set; }
    }
internalclass 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;}publicnewvoid 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框架也有用到这个,比如日志模块。所以感觉有必要了解一下,放个小例子作为结束:

internalclass Message
    {publicstring Notify {get;set; }
    }
internalclass Teacher : IObservable<Message>
    {privatereadonly List<IObserver<Message>> _observers;public Teacher()
        {
            _observers=new List<IObserver<Message>>();
        }public IDisposable Subscribe(IObserver<Message> observer)
        {
            _observers.Add(observer);returnnew Unsubscribe(observer, _observers);
        }publicvoid SendMessage(string message)
        {foreach (var observerin _observers)
            {
                observer.OnNext(new Message() { Notify ="message" });
            }
        }publicvoid OnCompleted()
        {foreach (var observerin _observers)
            {
                observer.OnCompleted();
            }
            _observers.Clear();
        }
    }internalclass Unsubscribe:IDisposable
    {privatereadonly IObserver<Message> _observer;privatereadonly List<IObserver<Message>> _observers;public Unsubscribe(IObserver<Message> observer, List<IObserver<Message>> observers)
        {this._observers = observers;this._observer = observer;
        }publicvoid Dispose()
        {if(_observers.Contains(_observer))
                _observers.Remove(_observer);
        }
    }
internalabstractclass Student : IObserver<Message>
    {privatestring name;public Student(string name)
        {this.name = name;
        }private IDisposable _unsubscribe;publicvirtualvoid OnCompleted()
        {
            Console.WriteLine("放学了...");
        }publicvirtualvoid OnError(Exception error)
        {
            Console.WriteLine("生病了...");
        }publicvirtualvoid OnNext(Message value)
        {
            Console.WriteLine($"大家好: 我是 {name} -_-");
            Console.WriteLine($"老师说:{value.Notify}");
        }publicvirtualvoid Subscribe(IObservable<Message> obserable)
        {if (obserable !=null)
                _unsubscribe= obserable.Subscribe(this);
        }
    }
internalclass StudentZhang : Student
    {public StudentZhang(string name) :base(name)
        {
        }
    }internalclass 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)

  • 作者:星仔007
  • 原文链接:https://www.cnblogs.com/morec/p/16138268.html
    更新时间:2022年5月22日10:07:20 ,共 8100 字。