2012-02-10 10 views
2

私は今、私が本当に興奮していないいくつかのコードをアプリケーションに持っています。私は(将来的に来てより多く持つ)これらのオブジェクトの1つを作成する必要がある自分のアプリケーション内のメソッドを持っているいくつかの基準に基づいて異なるタイプを作成する

class Base 
{ 
    // base properties ... 
} 

class DerivedA : Base 
{ 
} 

class DerivedB : Base 
{ 
} 

文字列プロパティに基づいて、データベースに格納されています。私はそうのようないくつかのクラスを作成しました。これらのオブジェクトのそれぞれがわずかに異なる場所からデータを取得しますが、私は今それをやっている方法があるかの大きなブロックであり、それは非常に保守思えません:

class BaseCreator 
{ 
    Base Create(string name) 
    { 
     if (name == "DerivedA") 
      return CreateDerivedA(); 
     else if(name == "DerivedB") 
      return CreateDerivedB(); 
    } 
} 

私いくつかの方法は何ですかこのコードをよりメンテナンス可能にするためにリファクタリングし、将来的に新しいタイプを追加することを容易にすることができますか?私はそれが何か違いがあれば私のアプリケーションで依存性注入(Ninject)を使用しています。

答えて

1

継承ツリーは、成長すると常に維持することが困難です。木が大きくなることを前もって知っているなら、継承の代わりに構図を真剣に考えてみてください。特にDIフレームワークをすでに使用している場合は、インターフェースが必要です。

+0

私は12種類以上の種類が追加されていることはありませんが、あなたが意味するものの例を挙げることができます。 DIコンテナを使用するために変換したものと、文字列に基づいてオブジェクトを構築することとの間に明白なリンクはありません。 –

+0

変換は、クラスからインタフェースへのベースでなければなりません。各タイプのBaseはインターフェースを実装することができ、これによりインターフェースの要件によってそれらの実装と契約(あなたの場合はBase)を管理することができます。文字列、列挙型または何かエラーを起こしにくいものにする。 DIコンテナにタイプ(新しいenumに基づいて)を基本契約にバインドさせ、DIコンテナで目的を返すインターフェイスを解決させます。 – OnResolve

+0

文字列はデータベースに格納されます。 –

1

あなたが本当に文字列を使用しなければならない場合は、リフレクションを使用することができます。

object GetInstance(string typeName) 
{ 
    Type.GetType(typeName).GetConstructor(Type.EmptyTypes).Invoke(new object[0]); 
} 

あなたはまた、辞書を使用することができます。このページに上陸他人のために

IDictionary<string, Func<object>> TypeMap = new Dictionary<string, Func<object>>() 
{ 
    { "TypeA",() => new TypeA() }, 
    { "TypeB",() => new TypeB() }, 
    { "TypeC",() => new TypeC() }, 
}; 

object GetInstance(string typeName) 
{ 
    return TypeMap[typeName](); 
} 

を、ジェネリック医薬品の使用を検討して、あなたの場合は、文字列を使用するを持っていない:

T CreateInstance<T>() 
    where T : new() 
{ 
    return new T(); 
} 
+0

@GuiltShowはい、私は文字列を使って2つの方法を提供しています。覚えておいて、私はあなたに答えるだけではありません。私はこのページに上陸したすべての人に答えています。 – Zenexer

+0

@GuiltShowあなたがもっと幸せになれば、私はその答えを明示します。ああ、申し訳ありません。私は通常、答を投稿します。 – Zenexer

+0

@GuiltShow今すぐ言いたいことがあります。 – Zenexer

1

私はあなたのif/elseswitch構造は悪いことではないことに注意します。悪いのは、同じif/elseまたはswitchと複数回表示されている場合です。あなたがうまくコードをデカップリングしている、あなたはそのどこかアプリケーション内のを知って、インタフェースまたは抽象ベースではなく、コンクリートにプログラミングしている

、あなたが必要とする特定の具体的なインスタンスを作成する方法を知っている何か。これはコードでも構いませんが、コンテナなどにすることもできますが、何かが存在しなければなりません。考えているのは何かがあるです。

これが存在する唯一の方法である限り、あなたのアプローチは問題ありません。このクラスの存在理由は、いくつかのインタフェースを満たす具体的なインスタンスを作成することです。変更の理由は、他の具体的な実装が追加(または削除)されていることです。

1

一般的なケースは、組成物および仕様パターンの使用のビットによって解決することができます。

public class Base 
{ 
    public abstract bool IsSatisfiedBy(string name); 

    // base properties ... 
} 

public class DerivedA : Base 
{ 
    public override bool IsSatisfiedBy(string name) 
    { 
     return name == "DerivedA"; 
    } 
} 

public class DerivedB : Base 
{ 
    public override bool IsSatisfiedBy(string name) 
    { 
     return name == "DerivedB"; 
    } 
} 

public class BaseCreator 
{ 
    private readonly IEnumerable<Base> candidates; 

    public BaseCreator(IEnumerable<Base> candidates) 
    { 
     this.candidates = candidates; 
    } 

    public Base Create(string name) 
    { 
     return this.candidates.First(c => c.IsSatisfiedBy(name)); 
    } 
} 
+0

辞書を持つ方が簡単かもしれませんが、理論的には同じ効率があると思います。 – Zenexer

+0

この特定のケースでは、辞書に相当するように見えますが、IsSatisfiedBy実装に何かを入れることができるので、コンベンションベースまたはアルゴリズムソリューションをさらに作成できます。このため、このソリューションは辞書よりも柔軟性があります。 –

+0

素敵な答えですが、DerivedAとDerivedBのプリインスタンス化されたクラスのリストを保持し、作成のセマンティクスが少し壊れていることが必要です。作成していないので、既存のインスタンスを返します。 。 – Anastasiosyal

0

はこの質問への一般的な答えはありません。抽象ファクトリは正しいかもしれませんが、これらの実装の違いと使用方法によって異なります。

テンプレート、戦略、状態、または他の同様のパターンを使用する必要があります。それらを見て、間違いなく抽象ファクトリーを見て、あなたの特定のシナリオに合ったパターンを決定してください。

関連する問題