BaseCollection
の契約は、そのadd
方法は、合法的に、その後UserCollection
の継承add
方法も同様に行う必要があり、Entity
から導出された任意のオブジェクトを渡すことができ、そしてそうする失敗はLSPの違反になることを指定した場合。 UserCollection
のみオーバーロードする可能性が特に適切ではないであろうけれども、元add
方法は、Entity
に由来する任意のオブジェクトで使用することができれば、LSPに違反しないタイプUser
のオブジェクトを受け入れadd
の過(上書きしない)を含んで有します。
場合は、代わりのadd
は、当該の方法は、派生クラスのベースでsetItem(int index, Entity value)
とsetItem(int index, User value)
のようなものだった、との契約は、それが唯一の外に読まれていたオブジェクトを操作することが保証されていたことを指定した場合同じコレクションの場合、UserCollection
を読み取ると、User
のインスタンス以外は決して返されません。メソッドは、LSPに違反することなくUser
のインスタンスではなかったすべてのオブジェクトを正当に拒否できます。 setItem
メソッドがuser
のインスタンスではないすべてを拒否しようとしている場合は、user
しか受け付けないオーバーロードを持つことが有用で適切かもしれません。たとえ継承されたsetItem
メソッドがvalue
がUser
のインスタンスを識別したことを確認する必要があったとしても、その型の引数を受け入れたオーバーロードは起こりません。このようなオーバーロードを追加する際の最大の注意点は、同じことを行う2つの非開封仮想メソッドの存在を避けるべきです。オーバーロードを追加する場合は、渡された引数をタイプUser
に変換し、メソッドのオーバーロードされたバージョンにチェーンするように、ベースクラスのメソッドをオーバーライドしてシールする必要があります。
配列は、後者の形式の契約および継承をサブスクライブします。タイプAnimal[]
の変数は、Cat[]
への参照を保持することができます。 Cat[]
を識別するAnimal[]
に任意のAnimal
を格納しようとすると失敗する可能性がありますが、Animal[]
から読み取られたAnimal
は同じ配列に「適合」することが保証されています。これにより、問題の配列の型を知らなくても、コードが任意の参照型の配列内の要素をソートまたは置換することが可能になります。
お返事ありがとうございます。 私の経験では、オーバーライドされたメソッドの引数の型を狭くする必要がある場合がよくあります。しかし、これはLSPに違反します。 どうすればこの問題に取り組むことができますか? –
あなた自身がLSPに違反していることが判明した場合、実際にはis-a関係がないことを意味します。継承は正しい選択ではありません。構成、いくつかの種類のテンプレート/ジェネリックソリューション、あるいは単純に2つの非関連クラスを代わりに考えてみてください。 – Attila
OKですが、実際の生活状況をモデル化する必要があることもあります。 たとえば、 'call(Doctor doctor)'メソッドを持つ 'Human'クラスがあります。そして、「子」クラスは「人間」を拡張します。しかし、「子供」は医者を受け入れることができません。彼は '医者 'を拡張する'小児科医 'だけを必要とする。だから、 '子ども'はこのようにメソッドをオーバーライドします: 'コール(小児科医)'。 'Child'は明らかに' Human'との関係があります。しかし、このクラスモデルはLSPに違反します。違反を克服する方法は? –