私の最初の質問は、コンストラクター宣言にもリスコフの原則が適用されているかということです。
つまり、コンストラクター内の(異なる)クラスごとにまったく同じ数/タイプのパラメーターを使用する必要がありますか?
これを見て:
package com.apptest.test;
public class Application {
public static void main(String[] args) {
IRepository r = new RepositoryUser("toto");
IRepository x = new BillingRepository("billing","super");
}
}
IRepositoryには2つの実装があることがわかりますが、1つはもう1つのパラメーターを使用します。
これは正しいですか、そしてリスコフの原則が尊重されていると言えますか?
すでにお察しのとおり、実装クラスのコンストラクターはインターフェースのAPIに参加していません。実際、コンストラクターをインターフェースの一部にしたくないでしょう。そうすることで、インターフェイスがクラスのインスタンス化方法に関する知識を持ち、Abstract Factory、Service Locator、DependencyInjectionなどのデザインパターンがほぼ確実に失敗することを意味します。
いいえ、インターフェースをコンストラクターに依存しないようにします。これにより、コンストラクターを介して、Reflectionを使用して、またはIoCコンテナーを使用して、実装クラスを適切と思われる方法でインスタンス化できます。
リスコフの置換原則 は、実際には何よりも行動を参照しています。クラスのサブタイプは機能を拡張する必要がありますが、プログラムのコンテキストで現在の機能を中断しない方法でのみ拡張する必要があります。
この点で、メソッドとコンストラクターは追加のパラメーターを取ることができます。秘訣は、プログラム全体でRepositoryUser
とBillingRepository
をIRepository
インスタンスとして交換可能に使用でき、どちらも同じように使用する必要があるということです。重要な違いは、実装の詳細にあり、他のどこにもありません。
インスタンスの構築もリスコフの原則に従う必要がありますが、コンストラクターが独自のロジックを実行している場合(メソッドの呼び出しなど)に限ります。ただし、通常はコンストラクターでこれを回避することがベストプラクティスであり、その場合は、リスコフの原則に関係するオブジェクトがどのようにインスタンス化されるかについて心配する必要はありません。