多个包装 - 如何做?

时间:2013-10-27 18:38:34

标签: c# oop design-patterns mvvm wrapper

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

UML View

现在,我正在尝试为Window创建一个视图模型,我希望它支持这三个接口(IWindowITitledWindowITopWindow )。它看起来像这样:

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();
    }
}

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

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

我想到的唯一解决方案是引入一个将它们联合起来的类(如TitledTopWindow),但是我必须为窗口的每个变体制作它并且太乱了(特别是后来当我引入新包装器来引入新功能。)

这样做的正确方法是什么?

更新:
在我的搜索中,我已经读过您使用包装器来扩展功能,但不是为了扩展API(这是一个目标)。

因此,如果无法按照我的预期方式解决此问题,我该如何以这种方式添加功能?

1 个答案:

答案 0 :(得分:2)

我的建议与

有关
 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)。