2

我为我的 WPF 应用程序编写了一个简单的中介(它是此处找到的代码的派生)。

public class Messenger
{
    private IDictionary<Type, IList<MessageObserver>> observers;

    public Messenger()
    {
        observers = new Dictionary<Type, IList<MessageObserver>>();
    }

    public IDisposeObserver AddObserver<TMessageType>(Action<TMessageType> handler) 
        where TMessageType : Message { }

    protected abstract void RemoveObserver<TMessageType>(Action<TMessageType> handler) 
        where TMessageType : Message { }

    public abstract void PostMessage<TMessageType>(TMessageType message) 
        where TMessageType : Message { }
}

Message只是一个空类,它为通过Messenger. 这个想法是您将从此类派生以创建具有相关数据的特定消息类(有点像EventArgs)。

我的实现不同的地方在于我想删除观察者的方式。我希望能够指定何时应以声明性方式删除它们,如下所示:

MessengerInstance.AddObserver<LoginMessage>(HandleLogin)
    .RemoveObserverWhen(message => message.LoginResult == LoginResult.Successful);

RemoveObserverWhen方法需要一个Predicate<T>whereT应该是AddObserver方法中指定的消息类型。

这里的想法是您可以在注册观察者本身的同一位置指定删除观察者的逻辑。然后,Messenger 类将在消息处理程序运行后检查谓词,如果谓词评估为真,则删除消息处理程序和删除处理程序。

每个消息处理程序都可以有任意数量的删除处理程序,因此我将其打包在一个名为MessageObserver.

public class MessageObserver : IDisposeObserver
{
    private IList<object> disposalHandlers;

    public MessageObserver(object observer)
    {
        Observer = observer;
        disposalHandlers = new List<object>();
    }

    public object Observer { get; private set; }

    public IList<object> DisposalHandlers
    {
        get { return disposalHandlers; }
    }

    public IDisposeObserver RemoveObserverWhen<T>(Predicate<T> predicate) 
        where T : Message
    {
        disposalHandlers.Add(predicate);
        return this;
    }
}

提供方法的MessageObserver工具。IDisposeObserverRemoveObserverWhen

public interface IDisposeObserver
{
    IDisposeObserver RemoveObserverWhen<T>(Predicate<T> predicate) 
        where T : Message;
}

这里的想法是IDisposeObserver可以返回一个实例,以便可以链接方法。

所有这些都有效,我的 viewModel 中有以下代码:

MessengerInstance.AddObserver<LoginMessage>(HandleLogin)
    .RemoveObserverWhen<LoginMessage>(message => message.LoginResult == LoginResult.Successful)
    .RemoveObserverWhen<LoginMessage>(SecondDisposalHandler);

我遇到的问题是,仅当我LoginMessage在调用RemoveObserver方法时指定泛型参数(在这种情况下)时才有效。我希望能够以文章开头描述的方式调用这些方法。

我认为我需要以某种方式返回一个泛型IDisposeObserver,但如果我进行此更改,则MessageObserver必须将其设为泛型,然后我无法指定约束,因为Messenger该类是非泛型的。

所以我的问题是,我的代码是否可以更新,以便在调用RemoveObserverWhen方法时不必指定消息类型,还是必须接受当前的解决方案?

注意:我知道还有其他可用的实现,但我这样做是为了帮助我理解 C# 中的面向对象设计原则和泛型,所以请不要向我指出其他实现的方向。

4

1 回答 1

3

我想我需要以某种方式返回一个通用的 IDisposeObserver 但如果我进行此更改,则必须将 MessageObserver 设为通用,然后我无法指定约束,因为 Messenger 类是非通用的。

您可能想要一个MessageObserver包含所有类型中性部分的非泛型基类,然后是一个实现泛型的泛型基类IDisposeObserver<T>。然后,您可以更改AddObserver为返回泛型IDisposeObserver<T>,但将字典保留在Messengeras 中IDictionary<Type, IList<MessageObserver>>。因此,为了清楚起见,您将拥有:

public interface IDisposeObserver<T>
{
    IDisposeObserver<T> RemoveObserverWhen(Predicate<T> predicate) 
        where T : Message;
}

public abstract class MessageObserver { ... }

public class MessageObserver<T> : MessageObserver, IDisposeObserver<T> { ... }

当您必须执行IDiposeObserver<T>.RemoveObserverWhen方法时,问题就来了 - 您可能只需将字典列表中的每个项目转换为IObserver<T>. 你会知道T那个时候,你会知道你已经正确地填充了列表。

当然,如果这是你对观察者唯一要做的事情,你可以只保留一个IDictionary<Type, IList<object>>,而不用打扰两个不同的MessageObserver类。这实际上取决于您是否从非泛型中获得任何价值。

于 2012-09-30T22:26:51.853 回答