2016-11-16 7 views
0

"I"のインターフェイス "I"と "I"の実装が "C1"〜 "Cn"とするとします。インターフェースとインプリメンテーションが変更できない外部ライブラリに存在するとします。最後に、Java 8を使用していると仮定します。

"I"のすべての実装の機能を拡張します。

"I"が変更可能な場合、OracleがストリーミングAPIを公開したときに、デフォルトの実装で新しいメソッドを追加することができます。残念ながら "私"は変更できません。

現在の解決策は次のとおりです。

"I"を拡張し、必要な新しいメソッドをデフォルトインターフェイスとして含む新しいインターフェイス "IX"を作成します。
"C1"〜 "Cn"は "IX"ではなく "I"を実装するため、新しい機能を利用するために実装 "CX1"〜 "CXn"が必要です。これは私が好きではない部分です。私は匿名のクラスのようにその場で実装を作成する方法を好むでしょう。 「CXN」に「CX1」の定義は、私はそれらの定型を考慮して取得したいと思い、まったく体の実装を必要としないので
これより少ないコードで既存のインターフェイス実装を拡張する方法はありますか?

// Instantiate existing "C9" implementation of "I" 
I object = new C9(); 

// Definition of interface "IX" 
public interface IX extends I { 
    default void newMethod() { 
    // Do something 
    } 
} 

// Example definition of implementation "CX9" 
// Off course, this needs to be done for all "C1" to "Cn". 
public class CX9 extends C9 implements IX {} 

// Instantiate extended implementation "C9" 
IX object = new CX9(); 

:ここ

は私のアプローチを説明するためにいくつかのコード例ですそれらを取り除く。私は実際に次のようなものを好むだろう。

IX object = new (C9 implements IX)() {}; 

もちろん、有効なJavaコードはありません。このアイデアは、追加インターフェイス(「IX」)を実装する既存のクラス(「C9」)に基づく匿名クラスを作成することです。標準のJavaでこれを行う方法はありますか?

私は間違いなく標準のJavaとバイトコード操作なしでこれをしたいと思います。もちろん、私はラッパーや動的なプロキシを使うことができますが、 "I"と "C"は多くのメソッドを定義しています。したがって、私はさらに定型的なコードで終わるだろう。

この質問は純粋に学術的なものであると認めます。なぜなら、結局のところ、「I」の実装ごとに1行のコードを削除するだけだからです。しかし、私はまだ可能な解決策に興味があります。

より実践的なアプローチが欲しい場合は、基本インターフェイスを変更することなく、未知の実装セットにストリーミングAPIのようなものを適用したいとします。

ありがとうございます。

+0

既存のCnクラスにはすべてデフォルトのコンストラクタしかないと言っていますか?そのすべてが容易にサブクラス化できるように? – GhostCat

+1

@PavneetSinghいいえ!いいえ!コードレビューでは、[トピック外の]疑似的な疑問を考慮します(http://codereview.stackexchange.com/help/on-topic)。 – Mast

+2

@PhilippSander上記のコメントを参照してください。誰かが起動すると、移行は拒否されます。私は確信しています。コードレビューはそれを受け付けません。 – Mast

答えて

0

IXインターフェイスを「ミキシング」しようとしていない場合は、空のボディを持つ匿名クラスがそのジョブを実行します。

IX object = new C9(){}; 

(これはC9はすでにIXを実装することを前提として)

objectC9の匿名のサブクラスのインスタンスです。 C9X不要をレンダリング

しかしC9はすでにC9を実装していない場合は、何も純粋なJavaソリューションをC9を変更から離れてはありません...。

C9にもIXを実装するように変更すると、良性でなければならないことに注意してください。まず、バイナリ互換性を損なうことはありません。

1

このようなことを解決する標準的な方法は、代表団です。私たちはあなたのIC1 ... C9種類について何も知らないので、私はデモのために一般的に知られているインターフェースを使用します:

public interface ExtSet<T> extends Set<T> { 
    default T reduce(BinaryOperator<T> op) { 
     Iterator<T> it = iterator(); 
     T t=it.next(); 
     while(it.hasNext()) t=op.apply(t, it.next()); 
     return t; 
    } 
    public static <T> ExtSet<T> enhance(Set<T> set) { 
     if(set instanceof ExtSet) return (ExtSet<T>)set; 
     final class Enhanced extends AbstractSet<T> implements ExtSet<T> { 
      public Iterator<T> iterator() { return set.iterator(); } 
      public int size() { return set.size(); } 
      public boolean contains(Object o) { return set.contains(o); } 
      public boolean add(T e) { return set.add(e); } 
      public boolean remove(Object o) { return set.remove(o); } 
     } 
     return new Enhanced(); 
    } 
} 

委任の実装が空の可能性と拡張クラスよりも多くの作業を行う必要がありますボディは、それだけで一度それをを行う必要があり、すなわち、でもそれを知らずに、すべてインタフェースの実装で

ExtSet<String> set1=ExtSet.enhance(new TreeSet<>()); 
Collections.addAll(set1, "foo", "bar", "baz"); 
System.out.println(set1.reduce(String::concat)); 

ExtSet<Integer> set2=ExtSet.enhance(new HashSet<>()); 
Collections.addAll(set2, 100, 42, 7); 
System.out.println(set2.reduce(Integer::sum)); 

ExtSet<Thread.State> set3=ExtSet.enhance(
           EnumSet.of(Thread.State.TERMINATED, Thread.State.NEW)); 
System.out.println(set3.reduce(BinaryOperator.minBy(Comparator.naturalOrder()))); 

これはどのようにのに似て動作します,synchronizedSet、およびunmodifiableSetは、既存のSetの実装を強化(または制限)します。

関連する問題