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 インターフェースが変更され、さらに多くのメソッドが追加されたため、すべての実装クラスが新しいメソッドを実装する必要があります。 問題は、それらを実装することは望ましくなく、多くの副作用につながる可能性があることです。 ここでは、 ローンの支払実装クラスは、 initializePayments() これは実際には必要ありません。 そのため、原則に違反しています。

したがって、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 の実装により、新しいメソッドが実装されたことに注意してください。 そして、それはそれらを必要とせず、それらのためのロジックを持っていないので、それは UnsupportedOperationExceptionをスローするだけです。 これが私たちが原則に違反し始めるところです。

次のセクションでは、この問題を解決する方法を説明します。

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から入手できます。