【问题标题】:Multiple Wrappers - How to do it?多个包装器 - 怎么做?
【发布时间】:2013-10-27 18:38:33
【问题描述】:

我有一个代表桌面窗口的Window 类,其中一些可以通过包装器 (TitledWindow) 命名,其中一些可以通过包装器 (TopWindow )。

现在,我正在尝试为Window 创建一个视图模型,并且我希望它支持这三个接口(@98​​7654327@、ITitledWindowITopWindow)。它看起来像这样:

public class WindowViewModel : ITopWindow, ITitledWindow
{
    private readonly IWindow _window;

    public WindowViewModel(IWindow window)
    {
        _window = window;
    }

    public IntPtr Handle
    {
        get { return _window.Handle; }
    }

    public Boolean? IsTopmost
    {
        get
        {
            var thisTopWindow = _window as ITopWindow;
            if (thisTopWindow == null)
                return null;
            return thisTopWindow.IsTopmost;
        }
        set
        {
            var thisTopWindow = _window as ITopWindow;
            if (thisTopWindow != null)
                thisTopWindow.IsTopmost = value;
        }
    }

    public String Title
    {
        get
        {
            var thisTitledWindow = _window as ITitledWindow;
            return thisTitledWindow == null ? null : thisTitledWindow.Title;
        }
    }
}

这就是我获得视图模型的方式:

public IList<WindowViewModel> OpenWindows
{
    get
    {
        var windowViewModels =
            from window in _windowEnumerator.EnumerateWindows()
            let titledWindow = new TitledWindow(window, _windowTitleReader)
            let topWindow = new TopWindow(titledWindow, _topmostManager)
            select new WindowViewModel(topWindow);
        return windowViewModels.ToList();
    }
}

问题是我只能获得层次结构中的 1st 包装器。

OpenWindows 中的所有窗口也是ITopWindow,但不是ITitledWindow,因为它将其包装在private readonly 字段中(可能应该保持这种方式)。

我想到的唯一解决方案是引入一个将它们合并的类(如TitledTopWindow),但我必须为窗口的每一个变化都做它,这太混乱了(尤其是稍后当我引入新的引入新功能的包装器)。

正确的做法是什么?

更新:
在我的搜索中,我读到您使用包装器来扩展功能,而不是扩展 API(这是这里的目标)。

那么如果这个问题不能按照我想要的方式解决,我该如何以这种方式添加功能?

【问题讨论】:

  • 如果您的样本接近您想要实现的目标,请考虑包含而不是继承:窗口可以包含可通过界面搜索的“特征”实例列表。
  • 是否必须将这些接口分开?如果没有,您可以将它们折叠到 Window 中,为所有操作提供默认/回退实现(如果需要,NotImplementedException),引入一个中间包装类,它将所有可选操作委托给被包装的实例,并让您的具体包装从它继承。然后,具体类会覆盖属于相应功能的方法。 (另请参阅Decorator pattern)但正如您所想象的那样,这仍然有其自身的缺点。
  • @AlexeiLevenkov 我会很感激一个例子或一个很好的参考。
  • @JayK 不能将界面折叠成Window。正如你所看到的,包装器/装饰器已经被使用了。这就是问题所在。

标签: c# oop design-patterns mvvm wrapper


【解决方案1】:

我的建议类似于

 class Window
 {
     List<object> traits;  

     T GetTrait<T>() 
     {
        return traits.Where(t => t.GetType() == typeof(T)).FirstOrDefault();
     } 
 }

 Window w;
 var topLevel = w.GetTrait<TopLevel>();
 if (topLevel != null)....

但是这个建议需要对接口/代码进行认真的修改。

我认为您确实想要遵循无效代码之类的东西,这样您就可以添加任意数量的包装器,并且仍然让所有接口在最终类上可见:

 class TopLevel<T> : T where T:Window

我认为你不能直接实现这一点(因为你不能从模板参数派生模板类)。

一种解决方法是在运行时生成派生类,添加必要的接口并代理内部类实现的所有接口。在Dynamically creating a proxy class(即A simple Dynamic Proxy)中讨论/链接的可能方法。

【讨论】:

  • 顺便说一句 - 你可以做return traits.OfType&lt;T&gt;().FirstOrDefault();
猜你喜欢
  • 1970-01-01
  • 2016-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-01
  • 2012-06-25
  • 1970-01-01
  • 2012-10-17
相关资源
最近更新 更多