5

次のクラス構造があるとします。

クラス構造

ページ

、およびインターフェイスは、クライアントによって実装されますPage。これらは、ページ タイプ (静的または動的) に応じてさまざまなデータを提供し、. これらのインターフェースには多くの実装があるかもしれません。StaticPageDynamicPageRenderer

レンダラー

Rendererページをレンダリングします。また、このインターフェースには複数の実装が存在する場合があります (さまざまなレンダリング手法用)。

レンダーマネージャー

これは、指定されたページ タイプに応じて、提供されたレンダラーで適切な render メソッドを呼び出すことになっている単なるファサードです。そして、ここにあります

問題

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. interface の代わりに抽象クラス。これにより、実装者の型階層に不必要な制約が課されます。実装者は、必要なクラスを拡張できなくなり、代わりに抽象StaticPageまたはDynamicPageクラスを拡張することを余儀なくされます。これは最悪です。

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

しかし、もちろん、動的型付けにはパフォーマンス コストが伴います。利点 - 新しいタイプのページが追加された場合、変更する必要があるのはレンダラーだけです。別のオーバーロードされたメソッドを追加するだけです。


別のオプションは訪問者です。この場合、各ページはディスパッチを行う必要があります(2番目のアプローチのようです):

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 に答える