Spring
のような多くのライブラリで、BeanNameAware
などの単一メソッドのインターフェイスを多数使用しているのを見てきました。
そして、実装者クラスは、単一のメソッドで多くのインターフェースを実装します。
どのようなシナリオで、単一のメソッドインターフェイスを維持することが理にかなっていますか?たとえばResultSet
のように、単一のインターフェイスがかさばるのを避けるために行われますか?または、これらのタイプのインターフェイスの使用を推奨する設計標準はありますか?
Java 8では、単一メソッドインターフェイスを維持すると、クロージャと「関数ポインタ」を使用できるため、非常に便利です。したがって、コードが単一メソッドインターフェイスに対して記述されている場合は常に、クライアントコードは、匿名クラスを作成する代わりに、クロージャまたはメソッド(単一のメソッドインターフェイスで宣言されたメソッドと互換性のある署名が必要)を渡すことができます。対照的に、複数のインターフェイスで1つのインターフェイスを作成する場合メソッドの場合、クライアントコードにはその可能性はありません。常に、インターフェイスのすべてのメソッドを実装するクラスを使用する必要があります。
したがって、一般的なガイドラインとして、次のように言うことができます。単一のメソッドのみをクライアントコードに公開するクラスが一部のクライアントに役立つ場合は、そのメソッドに単一のメソッドインターフェイスを使用することをお勧めします。これに対する反例はIterator
インターフェースです。ここでは、next()
メソッドなしでhasNext()
メソッドしかないのは役に立ちません。これらのメソッドの1つのみを実装するクラスを持つことは役に立たないため、このインターフェイスを分割することはここではお勧めできません。
例:
interface SingleMethod{ //The single method interface
void foo(int i);
}
class X implements SingleMethod { //A class implementing it (and probably other ones)
void foo(int i){...}
}
class Y { //An unrelated class that has methods with matching signature
void bar(int i){...}
static void bar2(int i){...}
}
class Framework{ // A framework that uses the interface
//Takes a single method object and does something with it
//(probably invoking the method)
void consume(SingleMethod m){...}
}
class Client{ //Client code that uses the framework
Framework f = ...;
X x = new X();
Y y = new Y();
f.consume(x); //Fine, also in Java 7
//Java 8
//ALL these calls are only possible since SingleMethod has only ONE method!
f.consume(y::bar); //Simply hand in a method. Object y is bound implicitly
f.consume(Y::bar2); //Static methods are fine, too
f.consume(i -> { System.out.println(i); }) //lambda expression. Super concise.
//This is the only way if the interface has MORE THAN ONE method:
//Calling Y.bar2 Without that closure stuff (super verbose)
f.consume(new SingleMethod(){
@Override void foo(int i){ Y.bar2(i); }
});
}
1つ(または少数)のメソッドのみを使用するインターフェイスは、非常に便利な 戦略パターン の鍵です。これは、「これらのタイプのインターフェイスの使用を推奨する設計標準」です。
もう1つの一般的なシナリオは、コールバックが必要な場合です。 FooはBarを非同期タスクとして呼び出し、Barが何かを終了すると、結果はコールバックを使用してFooに返送されます。コールバックは1つのメソッドのみを含むインターフェイスにすることができます。 (この例は、Androidの多くのリスナー、Swingのイベントリスナーです...)
また、互いに緊密に結合されている2つのクラスがある場合(それらをFooとBarと呼びましょう)。 FooはBarのほぼすべてのメソッドを使用しますが、Barが必要とするのはFooのメソッドの一部だけです。 FooはFooInterface
を実装でき、それがBarに送信されます。 BarはFooInterfaceについてのみ知っているが、実装クラスに含まれている他のメソッドについては気にしないため、結合は緩くなりました。
Favor Composition over Inheritance
のチュートリアルHead First Design Pattern
本は、クラスに動的に機能を追加するためにこのアプローチを推奨しています。以下の場合を考えてみましょう。
public interface Quackable {
public void quack();
}
public class Quacks implements Quackable {
public void quack(){
//quack behavior
}
}
public class DontQuack implements Quackable {
public void quack(){
//dont quack
}
}
public class QuackableDuck{
Quackable quack; //add behavior dynamicall
}
したがって、QuackableDuckクラスは機能を動的に追加できます。
quack = new Quacks();
//or
quack = new DontQuack();
したがって、同様に、クラスに複数の動作を動的に追加できます。
インターフェースは、その中のメソッドの数に応じて作成するのではなく、システムのコンポーネントが期待する動作を定義して、隣接するものに単一の責任を果たします。この単純な原則/ルールに従うと、定義する責任に応じて、単一のメソッドインターフェイスが作成される場合と終了しない場合があります。私はテストを愚かでシンプルにし、アプリケーションを非常に柔軟に保つのが好きなので、通常はそれらの多くを持っています
どのようなシナリオで、単一のメソッドインターフェイスを維持することが理にかなっていますか?
このようなシナリオでは、1つのメソッドのみのインターフェイスが必要です。
インターフェイスは、いくつかのクラスの一般的な動作をカプセル化するために使用されます。したがって、限られたクラスメソッドのセットのみを呼び出す必要があるコード内の場所が複数ある場合は、インターフェイスを導入するときが来ました。メソッドの数は、正確に何を呼び出す必要があるかによって異なります。 one メソッドが必要な場合もあれば、 two または more の場合もありますが、 メソッドはまったく必要ありません の場合もあります。重要なのは、動作を実装から分離できることです。