【发布时间】:2015-04-03 08:58:52
【问题描述】:
在这个应用程序中,观察者处理对象网络中的状态变化。所有对象都是基于同一个 BaseObject 类的派生类。 BaseObject 提供基本的识别和导航功能。
从 BaseObject 派生的类由代码生成器创建。这些类应具有最小的足迹并专注于特定的状态和行为。
在应用程序级别,观察者处理 BaseObject 派生类中的状态更改,通常针对多个类,并且主要针对大量 BaseObject 派生实例。
在当前的解决方案中,BaseObject 管理观察者,并以 BaseObject 实例作为发送者通知观察者。
using System;
using System.Collections.Generic;
namespace Observer {
#region underlying framework foundation
interface IObserver {
void ObjectChanged (BaseObject obj);
}
abstract class BaseObject {
HashSet<IObserver> observers = new HashSet<IObserver> ();
public void RegisterObserver (IObserver observer) {
observers.Add (observer);
}
public void FireObjectChanged () {
foreach (var obs in observers)
obs.ObjectChanged (this);
}
}
#endregion underlying framework foundation
#region code generator
class DerivedObject1 : BaseObject {
}
class DerivedObject2 : BaseObject {
}
#endregion code generator
#region application code
class Observer : IObserver {
public void ObjectChanged (BaseObject obj) {
Console.WriteLine (obj.GetType ().Name);
if (obj is DerivedObject1) {
} else if (obj is DerivedObject2) {
}
}
}
#endregion application code
#region sample
class Program {
static void Main (string[] args) {
Observer observer = new Observer ();
List<BaseObject> objects = new List<BaseObject> ();
DerivedObject1 obj1 = new DerivedObject1 ();
objects.Add (obj1);
obj1.RegisterObserver (observer);
DerivedObject2 obj2 = new DerivedObject2 ();
objects.Add (obj2);
obj2.RegisterObserver (observer);
foreach (var bo in objects)
bo.FireObjectChanged ();
}
}
#endregion sample
}
我不喜欢这种方法的是观察者必须在运行时识别发送者类型。相反,我想让它在编译时是安全的。
所以我提出了一种新方法,它引入了泛型和第二个 BaseObject 层,BaseObjectT,它拥有类型安全的观察者。
using System;
using System.Collections.Generic;
namespace Observer {
#region underlying framework foundation
interface IObserver<T> where T : BaseObjectT<T> {
void ObjectChanged (T obj);
}
abstract class BaseObject {
public abstract void FireObjectChanged ();
}
abstract class BaseObjectT<T> : BaseObject where T : BaseObjectT<T> {
HashSet<IObserver<T>> observers = new HashSet<IObserver<T>> ();
public void RegisterObserver (IObserver<T> observer) {
observers.Add (observer);
}
public override void FireObjectChanged () {
foreach (var obs in observers)
obs.ObjectChanged ((T)this);
}
}
#endregion underlying framework foundation
#region code generator
class DerivedObject1 : BaseObjectT<DerivedObject1> {
}
class DerivedObject2 : BaseObjectT<DerivedObject2> {
}
#endregion code generator
#region application code
class Observer :
IObserver<DerivedObject1>,
IObserver<DerivedObject2> {
public void ObjectChanged (DerivedObject1 obj) {
Console.WriteLine (obj.GetType ().Name);
}
public void ObjectChanged (DerivedObject2 obj) {
Console.WriteLine (obj.GetType ().Name);
}
}
#endregion application code
#region sample
class Program {
static void Main (string[] args) {
Observer observer = new Observer ();
List<BaseObject> objects = new List<BaseObject> ();
DerivedObject1 obj1 = new DerivedObject1 ();
objects.Add (obj1);
obj1.RegisterObserver (observer);
DerivedObject2 obj2 = new DerivedObject2 ();
objects.Add (obj2);
obj2.RegisterObserver (observer);
foreach (var bo in objects)
bo.FireObjectChanged ();
}
}
#endregion sample
}
虽然这种方法有效并且在应用程序级别完全符合我的要求 - 将派生类的实例传递给观察者而不需要在那里进行类型转换,并允许重载不同的 IObserver 方法实现 - 这似乎是在底层对我来说有点难看。
我现在的问题是,有没有更好、更优雅的方法来实现这一点,特别是有没有办法避免 FireObjectChanged() 中的演员表
obs.ObjectChanged ((T)this);
还是将 BaseObject 和 BaseObjectT 组合成一个基类?
【问题讨论】:
-
你不应该命名
IObserver<T>,除非它是,好吧IObserver<T>