Javaでのインターフェース分離の原則
1. 序章
このチュートリアルでは、SOLIDの原則の1つであるインターフェイス分離の原則について説明します。 「SOLID」で「I」を表す場合、インターフェイスの分離は、大きなインターフェイスを小さなインターフェイスに分割する必要があることを意味します。
したがって、クラスの実装が不要なメソッドを実装する必要がないことを確認します。
2. インターフェイス分離の原則
この原則は、RobertCによって最初に定義されました。 マーティンは次のように述べています。「クライアントは、使用しないインターフェースに依存するように強制されるべきではありません」。
この原則の目標は、アプリケーションインターフェイスを小さなインターフェイスに分割することで、大きなインターフェイスを使用することによる副作用を減らすことです。 これは、単一責任原則に似ており、各クラスまたはインターフェースが単一の目的を果たします。
正確なアプリケーション設計と正しい抽象化は、インターフェイス分離の原則の背後にある鍵です。 アプリケーションの設計段階ではより多くの時間と労力がかかり、コードの複雑さが増す可能性がありますが、最終的には柔軟なコードが得られます。
後のセクションで原則に違反している例をいくつか調べてから、原則を正しく適用することで問題を修正します。
3. サンプルインターフェイスと実装
実装BankPaymentで使用されるPaymentインターフェースがある状況を見てみましょう。
public interface Payment {
void initiatePayments();
Object status();
List<Object> getPayments();
}
そして実装:
public class BankPayment implements Payment {
@Override
public void initiatePayments() {
// ...
}
@Override
public Object status() {
// ...
}
@Override
public List<Object> getPayments() {
// ...
}
}
簡単にするために、これらのメソッドの実際のビジネス実装は無視しましょう。
これは非常に明確です。これまでのところ、実装クラス BankPayment には、Paymentインターフェイスのすべてのメソッドが必要です。 したがって、それは原則に違反しません。
4. インターフェイスの汚染
さて、時間の経過とともに、より多くの機能が登場するにつれて、LoanPaymentサービスを追加する必要があります。 このサービスも支払いの一種ですが、さらにいくつかの操作があります。
この新機能を開発するために、Paymentインターフェースに新しいメソッドを追加します。
public interface Payment {
// original methods
...
void intiateLoanSettlement();
void initiateRePayment();
}
次に、LoanPaymentの実装があります。
public class LoanPayment implements Payment {
@Override
public void initiatePayments() {
throw new UnsupportedOperationException("This is not a bank payment");
}
@Override
public Object status() {
// ...
}
@Override
public List<Object> getPayments() {
// ...
}
@Override
public void intiateLoanSettlement() {
// ...
}
@Override
public void initiateRePayment() {
// ...
}
}
現在、 Payment インターフェースが変更され、さらに多くのメソッドが追加されたため、すべての実装クラスが新しいメソッドを実装する必要があります。
したがって、BankPaymentクラスはどうなりますか。
public class BankPayment implements Payment {
@Override
public void initiatePayments() {
// ...
}
@Override
public Object status() {
// ...
}
@Override
public List<Object> getPayments() {
// ...
}
@Override
public void intiateLoanSettlement() {
throw new UnsupportedOperationException("This is not a loan payment");
}
@Override
public void initiateRePayment() {
throw new UnsupportedOperationException("This is not a loan payment");
}
}
BankPayment の実装により、新しいメソッドが実装されたことに注意してください。 そして、それはそれらを必要とせず、それらのためのロジックを持っていないので、それは
次のセクションでは、この問題を解決する方法を説明します。
5. 原則の適用
前のセクションでは、意図的にインターフェースを汚染し、原則に違反しました。 このセクションでは、原則に違反せずにローン支払いの新機能を追加する方法を検討します。
各支払いタイプのインターフェースを分類してみましょう。 現状:
クラス図で、前のセクションのインターフェイスを参照すると、両方の実装で status()メソッドと getPayments()メソッドが必要であることに注意してください。 一方、 initiatePayments()は BankPayment でのみ必要であり、 initializeLoanSettlement()および initializeRePayment()メソッドのみが必要です。 LoanPaymentの場合。
それを並べ替えたら、インターフェイスを分割して、インターフェイス分離の原則を適用しましょう。 したがって、共通のインターフェースができました。
public interface Payment {
Object status();
List<Object> getPayments();
}
そして、2つのタイプの支払いのためのさらに2つのインターフェース:
public interface Bank extends Payment {
void initiatePayments();
}
public interface Loan extends Payment {
void intiateLoanSettlement();
void initiateRePayment();
}
そして、 BankPayment で始まるそれぞれの実装:
public class BankPayment implements Bank {
@Override
public void initiatePayments() {
// ...
}
@Override
public Object status() {
// ...
}
@Override
public List<Object> getPayments() {
// ...
}
}
そして最後に、改訂された LoanPaymentの実装:
public class LoanPayment implements Loan {
@Override
public void intiateLoanSettlement() {
// ...
}
@Override
public void initiateRePayment() {
// ...
}
@Override
public Object status() {
// ...
}
@Override
public List<Object> getPayments() {
// ...
}
}
それでは、新しいクラス図を確認しましょう。
ご覧のとおり、インターフェースは原則に違反していません。実装は空のメソッドを提供する必要はありません。 これにより、コードがクリーンに保たれ、バグの可能性が減少します。
6. 結論
このチュートリアルでは、インターフェイス分離の原則に従うことから最初に逸脱した単純なシナリオを見て、この逸脱が引き起こす問題を確認しました。 次に、これらの問題を回避するために、原則を正しく適用する方法を示しました。
変更できない汚染されたレガシーインターフェイスを扱っている場合は、アダプタパターンが便利です。
インターフェイス分離の原則は、アプリケーションを設計および開発する際の重要な概念です。 この原則を順守することで、複数の責任を持つ肥大化したインターフェースを回避できます。 これは、最終的には単一責任の原則に従うのにも役立ちます。
いつものように、コードはGitHubでから入手できます。