2011-01-19 12 views
2

OOP言語が適切に活用されていない一般的な赤い旗が次のようになります。多型を使用するとタイプ固有の機能はどのように実装されますか?

if (typeof(x) == T1) 
{ 
    DoSomethingWithT1(x); 
} 
else if (typeof(x) == T2) 
{ 
    DoSomethingWithT2(x); 
} 

このような設計上の問題のための標準的な「修正」はどちらかの継承によって、T1T2の両方を共有インターフェースを作ることです共通インタフェースの基本型または実装(それをサポートする言語で)。例えば、C#でソリューションは次のようになります。

しかし
public interface IT 
{ 
    void DoSomething(); 
} 

が、時にはあなたは、オブジェクトの種類によって異なり機能を実装したいが、その機能はは、そのオブジェクトの型の中に属していません。したがって、多形性は間違った方法に見える。

たとえば、特定のデータの集まりを表示するUIの場合を考えてみましょう。このビューでは、表示されるデータの種類に応じてさまざまなレイアウトやコントロールをレンダリングすることができますが、if/else文を使用せずに、このタイプのレンダリングをどのように実装しますか?

I 希望が明らかなので、レンダリングロジックを型に入れることは、この場合非常に悪い決定として私に当てはまります。一方、データオブジェクトのタイプをビジュアルプレゼンテーションに結合することなく、if/elseのシナリオを回避するのは難しいです。

具体的な例を示します。私は、様々な市場製品に対してさまざまな価格設定モデルを使用する取引アプリケーションに取り組んでいます。これらの異なるモデルは、共通のPricingModelベースを継承するタイプによって表されます。各タイプは全く異なるパラメータのセットに関連付けられています。ユーザーが(特定の製品の)特定の価格設定モデルのパラメーターを表示する場合、現在、これらはモデルのタイプを検出し、適切なコントロールを表示するフォームで表示されます。私の質問は、現在よりももっとエレガントに実装できる方法です(大きなif/elseブロック)。

これはおそらく非常に基本的な質問のようです。それは、私が知っている(固体のOOPの原則 - 設計パターン - 常識?)のギャップの1つに過ぎないと思っていました。

答えて

1

私たちは、このような機能を辞書型にタイプインする(Spring.Net)。

IDictionary<Type, IBlahImplementor> blahImplementors; 

blahImplementors[thingy.GetType()].Do(thingy); 

この辞書は、機能を提供する一種のリポジトリによって管理することができます。そして、それはこのように辞書に追加され

interface IBlahImplementor 
{ 
    Type ForType { get; } 

    void Do(object thingy); 
} 

IEnumerably<IBlahImplementor> blahImplementors; 
foreach (var implementor in blahImplementors) 
{ 
    blahImplementors.Add(implementor.ForType, implementor); 
} 

を実装の詳細として

は、実装者は、通常、それ自体を提供することができ、それが依存するタイプを知っています

備考:IMHOでは、サブタイプ固有の実装を提供することにより、生活をはるかに容易にするものであっても、クラスに属さないものがあることを理解することは非常に重要です。


編集:最後に、あなたの具体的な例を理解します。

実際には、適切なUIコントロールをインスタンス化して価格モデルパラメータを表示することです。上記のパターンIで可能でなければならない。プライシングモデル用のUIコントロールが1つもない場合は、作成するか、必要なコントロールを設定するUIコンフィグレータなどを記述します。

interface IPricingModelUiConfigurer 
{ 
    Type PricingModelType { get; } 
    void SetupUi(Control parent, IPricingModel model); 
} 
0

Visitor Patternの使用例は説明したとおりです。

EDIT:代わりに大きなif使用するのでは、今

// interface used to add external functionality to pricing models 
public interface PricingModelVisitor { 
    void visitPricingModel1(PricingModel1 m); 
    void visitPricingModel2(PricingModel2 m); 
    ... 
} 
// your existing base-class, with added abstract accept() method to accept a visitor 
public abstract class PricingModelBase { 
    public abstract void accept(PricingModelVisitor v); 
    ... 
} 
// concrete implementations of the PricingModelBase implement accept() by calling the 
// appropriate method on the visitor, passing themselves as the argument 
public class PricingModel1 : PricingModelBase { 
    public void accept(PricingModelVisitor v) { v.visitPricingModel1(this); } 
    ... 
} 
public class PricingModel2 : PricingModel { 
    public void accept(PricingModelVisitor v) { v.visitPricingModel2(this); } 
    ... 
} 
// concrete implementation of the visitor interface, in this case with the new 
// functionality of adding the appropriate controls to a parent control 
public class ParameterGuiVisitor : PricingModelVisitor { 
    private Control _parent; 
    public ParameterGuiVisitor(Control parent) { _parent = parent; } 
    visitPricingModel1(PricingModel1 m) { 
     // add controls to _parent for PricingModel1 
    } 
    visitPricingModel2(PricingModel2 m) { 
     // add controls to _parent for PricingModel1 
    } 
} 

- あなたが編集コントロールを表示する必要がある場合elseブロック:あなたの具体的な例について、あなたはこのようなビジターパターンを適用することができPricingModelVisitorの特定のサブタイプのパラメータは、あなたが単に

somePricingModel.accept(new ParameterGuiVisitor(parentControl)) 

を呼び出すことができ、それはあなたのために適切なGUIを移入します。

+0

ビジターは、おそらく十分な柔軟性がありません。訪問型を動的に追加することはできません。ビジターの実装を動的に追加することができます。 –

+0

「訪問したタイプを動的に追加する」とはどういう意味ですか?ビジターパターンでは、この新しいタイプを扱うビジターインターフェイスに新しいメソッドを追加するだけで、簡単に新しいタイプを追加できます。コンパイル時に、この新しいタイプを適切に処理するために、既存のすべての訪問者実装を更新する必要があります。これは、辞書ベースのソリューションでは見過ごされる可能性があります。 –

+0

時には注入、簡単な型の登録、実行時の型の追加、ビジターインタフェースなどを指定するアセンブリでは知られていない型の追加などがあります。 *おそらく十分柔軟ではない*ここに記載された問題のため。 –

0

あなたが記述しているように共通のインタフェースのアプローチを使用して、 "機能がそのオブジェクトのタイプに属していない"というメソッドをトリガするコマンドパターンを使用できます。私はこれがOOPの基本原則を壊さないと思います。

関連する問題