5

假设我有以下类结构:

类结构

和接口由客户端实现Page。它们根据页面类型(静态或动态)提供各种数据,由. 这些接口可能有很多实现。StaticPageDynamicPageRenderer

渲染器

Renderers 呈现页面。此外,此接口可能有多种实现(针对不同的渲染技术)。

渲染管理器

这只是一个简单的外观,它应该根据给定的页面类型在提供的渲染器上调用适当的渲染方法。这里是

问题

如何Renderer根据提供的页面类型确定在对象上调用哪个方法?

当前(不满意)的解决方案

目前我正在使用条件调度:

void render(Page page, Renderer renderer) {
    if (page is StaticPage) {
        renderer.renderStaticPage(page);
    } else if (page is DynamicPage) {
        renderer.renderDynamicPage(page);
    } else {
        throw new Exception("page type not supported");
    }
}

怎么了

这个解决方案的问题是,每当我想添加另一种页面类型(即扩展Page界面)时,我也需要调整这个方法。实际上,这就是面向对象语言中的多态(虚拟)方法应该用于的用途,但在这种情况下这不起作用(见下文原因)。

我考虑过但拒绝的其他解决方案

  1. 抽象类而不是接口。这将对实现者的类型层次结构施加不必要的约束:他们将不再能够扩展他们想要的任何类,而是被迫扩展抽象StaticPageDynamicPage类,这很糟糕。

  2. 向接口添加一个dispatch(Renderer render)方法,并强制实现者根据页面类型调用渲染器对象上的适当方法。这显然很糟糕,因为实现者不应该关心渲染:他们只需要提供要渲染的数据。

那么,也许有一些模式或一些替代设计可能在这种情况下有所帮助?欢迎任何想法。:)

4

1 回答 1

4

用于dynamic在运行时选择适当的方法重载:

public class RenderManager
{
    public void Render(IPage page, Renderer renderer)
    {
        try
        {
            renderer.RenderPage((dynamic)page);
        }
        catch (RuntimeBinderException ex)
        {
            throw new Exception("Page type not supported", ex);
        }
    }
}

但是,动态类型当然有性能成本。好处 - 添加新类型的页面时,您需要更改的只是渲染器 - 只需添加另一个重载方法。


另一种选择是访客。在这种情况下,每个页面都应该进行调度(似乎是您的第二种方法):

public interface IPage
{
    void Render(Renderer renderer);
}

public class StaticPage : IStaticPage
{
    public void Render(Renderer renderer)
    {
        renderer.RenderPage(this);
    }
}

public class RenderManager
{
    public void Render(IPage page, Renderer renderer)
    {
        page.Render(renderer);
    }
}

在这种情况下,页面“知道”渲染。添加新页面时,您仍然应该修改渲染器。

于 2013-09-06T10:30:11.780 回答