15

インターフェイスを返したいのですが、switch ステートメント内で設定したいと思います。これはデザインが悪いのでしょうか?

private IResultEntity GetEntity(char? someType)
    {
        IResultEntity entity = null;

        switch (someType)
        {
            case 'L': //life
                entity = new LifeEntity();
                break;
            case 'P': //property
                entity = new PropertyEntity();
                break;
            case 'D': //disability
                entity = new DisabilityEntity();
                break;
            case 'C': //credit card
                entity = new CreditCardEntity();
                break;
        }

        return entity;
    }
4

6 に答える 6

20

ファクトリで事前に作成するすべての派生クラスをグループ化して制御できる場合は、通常、ファクトリでswitchステートメントを使用してもかまいません。

場合によっては、ユーザーが作成したプラグインが独自のクラスをそのスイッチリストに追加したい場合、swichステートメントでは不十分なことがあります。

より強力で用途の広いファクトリークラスの作成に関する詳細については、この優れた情報源を見つけました。

私が通常採用する適切な中間アプローチは、ファクトリクラスごとに静的なDictionary <string、Type>を保持することです。

ある種の実装を使用して、自分の実装を「登録」することができます。

Factories.TypeRegistration.StaticDictionary.Add("somekey",typeof(MyDerivedClass))

(または、Registrationメソッドを使用して、StaticDictionaryを非表示にすることをお勧めします)

次に、ファクトリには、テーブルでルックアップを実行することによってインスタンスを作成する簡単なタスクがあります。

Activator.CreateInstance(Factories.TypeRegistration.StaticDictionary["somekey"]);
于 2009-07-29T00:29:44.710 に答える
4

C# でどのような可能性があるかはわかりませんが、あちこちにスイッチを配置するよりも、ファクトリ メソッドに 1 つのスイッチを配置する方がよいでしょう。工場出荷時の方法では、切り替えは許容されますが、十分に文書化されている方がよいでしょう。

于 2009-07-28T23:45:28.193 に答える
3

設定ファイルの特定の値に対してインスタンス化するタイプが必要です。何かのようなもの:

<TypeMappings>
<TypeMapping name = "life" type = "Entities.LifeEntity、Entities" />
<TypeMapping name = "property" type = "Entities.PropertyEntity、Entities" />
<TypeMapping name = "disability" type = "Entities .DisabilityEntity、Entities "/>
<TypeMapping name =" creditcard "type =" Entities.CreditCardEntity、Entities "/>
</ TypeMappings>

メソッド内で、構成ファイルからすべての登録を抽出し、一致するものを見つけ、リフレクションを使用してタイプをインスタンス化できます。登録が見つからない場合は、例外をスローします。

サンプルコードは次のとおりです。

namespace Entities
{

public interface IResultEntity
{
}

public class LifeEntity : IResultEntity
{
    public override string ToString()
    {
        return("I'm a Life entity");
    }
}

public class PropertyEntity : IResultEntity
{
    public override string ToString()
    {
        return("I'm a Property Entity");
    }
}

public class CreditCardEntity : IResultEntity
{
    public override string ToString()
    {
        return("I'm a CreditCard Entity ");
    }
}

public class DisabilityEntity : IResultEntity
{
    public override string ToString()
    {
        return("I'm a Disability Entity");
    }
}

}

    public static Entities.IResultEntity GetEntity(string entityTypeName,string fileName)
{
    XDocument  doc = XDocument.Load(fileName);
    XElement element = doc.Element("TypeMappings").Elements("TypeMapping")
                               .SingleOrDefault(x => x.Attribute("name").Value == entityTypeName);        

    if(element == null)
    {
        throw new InvalidOperationException("No type mapping found for " + entityTypeName);
    }   
    string typeName = element.Attribute("type").Value;
    Type type = Type.GetType(typeName);
    Entities.IResultEntity resultEntity = Activator.CreateInstance(type) as Entities.IResultEntity;
    if(resultEntity == null)
    {
        throw new InvalidOperationException("type mapping for " + entityTypeName +  " is invalid");
    }
    return resultEntity;
}

    public static void Main()
{
    try
    {
        Entities.IResultEntity result = GetEntity("life", @"c:\temp\entities.xml");
        Console.WriteLine(result);

         result = GetEntity("property", @"c:\temp\entities.xml");
        Console.WriteLine(result);

         result = GetEntity("disability", @"c:\temp\entities.xml");
        Console.WriteLine(result);          

         result = GetEntity("creditcard", @"c:\temp\entities.xml");
        Console.WriteLine(result);          

         result = GetEntity("foo", @"c:\temp\entities.xml");
        Console.WriteLine(result);      

    }
}

多くのDIフレームワークでは、メタデータに基づいてクエリできるインターフェイスに複数の登録を提供できます。MEFがメタデータを使用してエクスポートを行う方法については、このリンクを確認してください。

于 2009-07-29T01:55:44.110 に答える
2

悪くはありませんが、Gang of Four Bible自体の例(パラメーター化されたファクトリメソッド)とほぼ同じです。

私は以前、switchステートメントはコードの臭いであると思っていましたが、そうではありません。オブジェクト指向言語での位置付けがあります。

于 2009-07-31T07:24:57.357 に答える
2

設計が悪いとは言いませんが、かなり剛性が高い可能性があります。これを拡張する唯一の方法は、再コンパイルを介することです。

于 2009-07-28T23:45:00.580 に答える
2

これで何も問題ないと思います。はい、switch ステートメントはコードの匂いがしますが、私の本では、この種の状況では問題ありません。このようなことを達成するために実際にできることは他にほとんどありません。

于 2009-07-28T23:56:00.823 に答える