3

私は現在、いくつかの古いC#コードを使用しています。これは、基本的に、次のような「プロパティ」としてTypeを使用することのみを目的として派生型を使用します。

public abstract class Fruit
{
    public int Property { get; set; }
}

public class Apple : Fruit {}

public class Pear : Fruit {}

その後:

public void Foo(Fruit item)
{
    if(item is Apple)
    {
        // do something
        return;
    }
    if(item is Pear)
    {
        // do something
        return;
    }

    throw new ArgumentOutOfRangeException("item");
}

'type'を指定するためにBaseClassにenumプロパティを含めたでしょう:

public class Fruit
{
    public int Property { get; set; }

    public FruitType Type { get; set; }
}

public enum FruitType
{
    Apple,
    Pear
}

そしてそれをこうして使用しました:

public void Foo(Fruit item)
{
    switch(item.Type)
    {
        case FruitType.Apple:
            // do something
            break;
        case FruitType.Pear:
            // do something
            break;
        default:
            throw new ArgumentOutOfRangeException();
    }
}

前者のパターンは継承の誤用だと思いますが、このコードを書き直す前に考慮すべき利点はありますか?

4

1 に答える 1

12

この状況に対処するための標準的な「OO」の方法は、DoSomethingをFruitの抽象的なメソッドにすることです。次に、呼び出し元はDoSomethingを呼び出すだけで、実装が正しいことを行うことを知っています。

このアプローチの欠点は、ユーザーが抽象クラスの作成者に望む可能性のあるすべての「何か」を解決する責任を負わせることです。

この欠点は、「ビジターパターン」を使用することで軽減できます。ビジターパターンは、サードパーティが値のランタイムタイプに基づいて動作を効率的に切り替えることができるようにするための標準的な方法です。あなたはそれを研究することを検討するかもしれません。

2番目のアプローチ(タグでタイプを識別する)は非常に一般的であり、非常に効率的です。Roslynはこの手法を幅広く使用しています。OOの純粋主義者は少し臭いと考えていますが、幸い私はOOの純粋主義者ではありません。

私が好きな2番目のテクニックのバリエーションは次のとおりです。

public enum FruitKind { Apple, Orange }
public abstract class Fruit
{
  private Fruit(FruitKind kind)
  {
      this.Kind = kind;
  }
  public FruitKind Kind { get; protected set; }
  private class Apple : Fruit
  {
      public Apple() : base(FruitKind.Apple) {}
  }
  public static Fruit MakeApple() { return new Apple(); }
  // similarly for orange
}

現在、Fruitユーザーがタイプを判別できる唯一の方法は、タグを使用することです。これは、AppleとOrangeにアクセスできないためです。唯一のFruitコンストラクターはプライベートであるため、サードパーティが独自のFruitを作成することはありません。

于 2013-01-22T00:42:45.890 に答える