훌륭한 사용 사례는 내가 "레버 (lever)"인터페이스라고 부르는 것입니다. 적은 수의 추상 메소드 (이상적으로는 1) 만 있지만 많은 기능을 제공한다는 점에서 많은 "레버리지"를 제공하는 인터페이스입니다. 클래스에서 1 개의 메소드를 구현해야하지만 "무료로"다른 메소드를 많이 얻으십시오. 단일 추상적으로, 예를 들어, 수집 인터페이스 생각 foreach
방법 및 default
방법처럼 map
, fold
, reduce
, filter
, partition
, groupBy
, sort
, sortBy
, 등
다음은 몇 가지 예입니다. 로 시작하겠습니다 java.util.function.Function<T, R>
. 단일 추상 방법이 R apply<T>
있습니다. 또한 두 가지 기본 방법을 사용하여 이전 또는 이후의 두 가지 방법으로 다른 함수로 함수를 구성 할 수 있습니다. 이러한 구성 방법은 모두 다음을 사용하여 구현됩니다apply
.
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
return (T t) -> after.apply(apply(t));
}
비슷한 객체에 대한 인터페이스를 다음과 같이 만들 수도 있습니다.
interface MyComparable<T extends MyComparable<T>> {
int compareTo(T other);
default boolean lessThanOrEqual(T other) {
return compareTo(other) <= 0;
}
default boolean lessThan(T other) {
return compareTo(other) < 0;
}
default boolean greaterThanOrEqual(T other) {
return compareTo(other) >= 0;
}
default boolean greaterThan(T other) {
return compareTo(other) > 0;
}
default boolean isBetween(T min, T max) {
return greaterThanOrEqual(min) && lessThanOrEqual(max);
}
default T clamp(T min, T max) {
if (lessThan( min)) return min;
if (greaterThan(max)) return max;
return (T)this;
}
}
class CaseInsensitiveString implements MyComparable<CaseInsensitiveString> {
CaseInsensitiveString(String s) { this.s = s; }
private String s;
@Override public int compareTo(CaseInsensitiveString other) {
return s.toLowerCase().compareTo(other.s.toLowerCase());
}
}
또는 Collection
원래 유형이 무엇이든 관계없이 모든 컬렉션 작업이 반환되는 매우 단순화 된 컬렉션 프레임 워크 :
interface MyCollection<T> {
void forEach(java.util.function.Consumer<? super T> f);
default <R> java.util.Collection<R> map(java.util.function.Function<? super T, ? extends R> f) {
java.util.Collection<R> l = new java.util.ArrayList();
forEach(el -> l.add(f.apply(el)));
return l;
}
}
class MyArray<T> implements MyCollection<T> {
private T[] array;
MyArray(T[] array) { this.array = array; }
@Override public void forEach(java.util.function.Consumer<? super T> f) {
for (T el : array) f.accept(el);
}
@Override public String toString() {
StringBuilder sb = new StringBuilder("(");
map(el -> el.toString()).forEach(s -> { sb.append(s); sb.append(", "); } );
sb.replace(sb.length() - 2, sb.length(), ")");
return sb.toString();
}
public static void main(String... args) {
MyArray<Integer> array = new MyArray<>(new Integer[] {1, 2, 3, 4});
System.out.println(array);
// (1, 2, 3, 4)
}
}
이러한 "레버"인터페이스는 람다 (SAM 인터페이스)로 구현 될 수 있기 때문에 람다와 함께 사용하면 매우 흥미로워집니다.
이것은 확장 메소드가 C♯에서 추가 된 것과 동일한 유스 케이스이지만 기본 메소드에는 한 가지 뚜렷한 장점이 있습니다. "적절한"인스턴스 메소드입니다. 즉, 인터페이스의 개인 구현 세부 사항에 액세스 할 수 있습니다 ( private
인터페이스 메소드가 제공됨). 확장 메소드는 정적 메소드의 구문 설탕 일뿐입니다.
Java가 Interface Injection을 받으면 형식이 안전하고 범위가 지정된 모듈 식 원숭이 패치도 가능합니다. 예를 들어 JRuby는 Java 클래스를 상속하거나 랩하여 추가 Ruby 의미를 제공하지만 이상적으로는 동일한 클래스를 사용하려고합니다. 인터페이스 주입과 기본 메소드를 사용하면 예를 들어 RubyObject
인터페이스를 주입 할 수 java.lang.Object
있으므로 Java Object
와 Ruby Object
가 완전히 동일 합니다.