6

私が最近取り組んだプロジェクトで、階層に属するクラスを受け入れるいくつかのメソッドに、次のようなコードがあることに気付きました。

public void Process(Animal animal) {
    if(animal.GetType() == typeof(Dog)) {
        Console.WriteLine("We have a dog");
    }
    else {
        Console.WriteLine("not a dog");
    }
}

さて、それはLSPのあからさまな違反だと思いました。なぜなら今、製品コード、ユニット テスト モック、または依存性注入インターセプターの一部としてdog のサブクラスを使用すると、このコードは同じようには機能しないからです。この特定のシナリオは、条件を次のように変更することで簡単に修正できると思います。

  if (animal is Dog)

しかし、それは私に考えさせました:

クライアント コードで LSP を壊す可能性がある他の落とし穴はありますか?

アップデート

明確にするために、階層内のクラスを使用するコードで起こりうる落とし穴を探しています。私は認識しており、ひどく構築された階層に関する問題を探していません-(例: 長方形 - 正方形の問題)。コードが元のクラスを処理するのと同じ方法で動的モック、インターセプター、装飾されたクラス (LoggingDog など) をサポートすることを確認するために、何を探すべきかを見つけようとしています。

これまでのところ、回答とリンクを調べた後、クラスの型を直接使用することが唯一の落とし穴であることがわかります。つまり、GetType()メソッドを直接使用するか、他のテクノロジーを介して使用します。ここにいくつかのコメントisas演算子がありますが、この場合、サブクラスは元のクラスと同じ方法で評価されるため、基本型へのキャストでさえ LSP を壊しません。

4

1 に答える 1

4

特定の型にキャストする必要がある場合が実際にあることを今のところ無視すると、ほとんどの場合、設計を変更することで問題を解決できます。

public class Animal
{
    public virtual void Process()
    {
        Console.WriteLine("Animal (not a dog)");
    }
}

public class Dog : Animal
{
    public override void Process()
    {
        Console.WriteLine("We have a dog");
    }
}

この設計を使用することで、動物を処理するコードにキャストする必要がなくなります。

var animal = ...; // maybe a Dog, maybe not
animal.Process();
于 2013-02-03T14:33:45.200 に答える