オープンおよびクローズの原則、リヒター置換の原則、依存関係の逆転の原則、および単一責任の原則に加えて、オブジェクト指向の設計原則には、インターフェース分離の原則、ディミットの原則および複合再利用の原則も含まれます。このセクションでは、インターフェース分離の原則について詳しく説明します。
インターフェース分離原理の定義
インターフェース分離原則(ISP)では、肥大化したインターフェースをできるだけ小さく、より具体的なインターフェースに分割して、顧客が関心を持つメソッドのみがインターフェースに含まれるようにする必要があります。
2002年、ロバートC.マーティンは、「インターフェース分離の原則」を次のように定義しました。クライアントが使用しないメソッドに依存するよう強制されるべきではありません。この原則には別の定義があります。あるクラスの別のクラスへの依存関係は、可能な限り最小のインターフェースに依存する必要があります。
上記の2つの定義の意味は、呼び出しに依存するすべてのクラスに対して非常に大きなインターフェースを確立するのではなく、各クラスに必要な専用インターフェースを確立することです。
インターフェースの分離と単一の責任の原則は、クラスの凝集性を改善し、クラス間の結合を減らすことであり、カプセル化の概念を反映していますが、2つは異なります:
- 単一の責任の原則は責任に焦点を合わせ、インターフェース分離の原則はインターフェースの依存関係の分離に焦点を合わせます。
- 単一責任の原則は、主にプログラムの実装と詳細を目的とする制約クラスです。インターフェース分離の原則は、主にインターフェースを制約し、主に抽象化とプログラムの全体的なフレームワークの構築を目的としています。
インターフェース分離原理の利点
インターフェース分離の原則は、インターフェースを制限し、インターフェースへのクラスの依存性を減らすことです。インターフェース分離の原則に従うと、次の5つの利点があります。
- 肥大化したインターフェースを細かい粒度で複数のインターフェースに分解すると、外部の変更の拡散を防ぎ、システムの柔軟性と保守性を向上させることができます。
- インターフェイスの分離により、システムの凝集性が向上し、外部の相互作用が減少し、システムの結合が減少します。
- インターフェースの粒度の定義が妥当であれば、システムの安定性は保証されます。ただし、定義が小さすぎると、インターフェースが多すぎて設計が複雑になります。定義が大きすぎると、柔軟性が低下し、カスタマイズされたサービスを提供できなくなります。プロジェクト全体には予期せぬリスクが伴います。
- インターフェース全体の定義はインターフェースの継承を通じて実現できるため、複数の専用インターフェースの使用はオブジェクトのレベルを反映することもできます。
- プロジェクトエンジニアリングにおけるコードの冗長性を削減できます。通常、大規模なインターフェイスには未使用のメソッドが多数あり、大きすぎるため、このインターフェイスを実装する場合、冗長なコードを設計する必要があります。
インターフェース分離原理の実装方法
インターフェース分離原理の特定のアプリケーションでは、次のルールに従って測定する必要があります。
- インターフェイスはできるだけ小さくする必要がありますが、制限されます。インターフェイスは、1つのサブモジュールまたはビジネスロジックのみを処理します。
- インターフェイスに依存するクラスのサービスをカスタマイズします。呼び出し元が必要とするメソッドのみを提供し、不要なメソッドをブロックします。
- 環境を理解し、盲目的に従うことを拒否します。各プロジェクトまたは製品には選択された環境要因があり、環境が異なれば、インターフェースの分割やビジネスロジックの詳細な理解に関する標準も異なります。
- 結束を改善し、外部の相互作用を減らします。インターフェースが最小限のメソッドを使用して、ほとんどのことを実行できるようにします。
以下では、生徒の成績管理プログラムを例として使用して、インターフェース分離の原則のアプリケーションを紹介します。
[例1]学生のパフォーマンス管理プログラム。
分析:生徒の成績管理プログラムには、通常、スコアの挿入、スコアの削除、スコアの変更、合計スコアの計算、平均スコアの計算、スコア情報の印刷、スコア情報のクエリなどの機能が含まれています。これらすべての機能を1つのインターフェースに配置することは明らかに合理的ではありません。 、正しい方法は、これらを入力モジュール、統計モジュール、および印刷モジュールの3つのモジュールに配置することですクラス図を図1に示します。
図1生徒のパフォーマンス管理プログラムのクラス図
プログラムコードは次のとおりです。
package principle;
public class ISPtest {
public static void main(String[] args) {
InputModule input =StuScoreList.getInputModule();
CountModule count =StuScoreList.getCountModule();
PrintModule print =StuScoreList.getPrintModule();
input.insert();
count.countTotalScore();
print.printStuInfo();
//print.delete();
}
}
// 输入模块接口
interface InputModule {
void insert();
void delete();
void modify();
}
// 统计模块接口
interface CountModule {
void countTotalScore();
void countAverage();
}
// 打印模块接口
interface PrintModule {
void printStuInfo();
void queryStuInfo();
}
// 实现类
class StuScoreList implements InputModule,CountModule,PrintModule {
private StuScoreList(){}
public static InputModule getInputModule() {
return (InputModule)new StuScoreList();
}
public static CountModule getCountModule() {
return (CountModule)new StuScoreList();
}
public static PrintModule getPrintModule() {
return (PrintModule)new StuScoreList();
}
public void insert() {
System.out.println("输入模块的insert()方法被调用!");
}
public void delete() {
System.out.println("输入模块的delete()方法被调用!");
}
public void modify() {
System.out.println("输入模块的modify()方法被调用!");
}
public void countTotalScore() {
System.out.println("统计模块的countTotalScore()方法被调用!");
}
public void countAverage() {
System.out.println("统计模块的countAverage()方法被调用!");
}
public void printStuInfo() {
System.out.println("打印模块的printStuInfo()方法被调用!");
}
public void queryStuInfo() {
System.out.println("打印模块的queryStuInfo()方法被调用!");
}
}
プログラムの結果は次のとおりです。
输入模块的insert()方法被调用!
统计模块的countTotalScore()方法被调用!
打印模块的printStuInfo()方法被调用!
<単一責任原則 ディミットの法則>