英語では、同形異義語のペアは、スペルが同じで意味が異なる 2 つの単語です。
ソフトウェア エンジニアリングでは、ホモグラフィック手法のペアとは、名前が同じで要件が異なる 2 つの手法です。質問をできるだけ明確にするために、不自然な例を見てみましょう。
interface I1 {
/** return 1 */
int f()
}
interface I2 {
/** return 2*/
int f()
}
interface I12 extends I1, I2 {}
どうすれば実装できI12
ますか? C#にはこれを行う方法がありますが、Java にはありません。したがって、唯一の回避策はハックです。リフレクション/バイトコードのトリック/その他を最も確実に使用するにはどうすればよいですか(つまり、完璧なソリューションである必要はありません。最適なソリューションが必要なだけです)。
合法的にリバース エンジニアリングできない既存のクローズド ソースの大規模なレガシー コードには、型のパラメーターが必要であり、その両方をパラメーターとして持つコードとパラメーターとして持つコードI12
に委任することに注意してください。したがって、基本的には、いつ として機能する必要があるか、いつとして機能する必要があるかを知るのインスタンスを作成する必要があります。これは、直接の呼び出し元の実行時にバイトコードを調べることで実行できると思います。これは単純なコードであるため、呼び出し側でリフレクションが使用されていないと想定できます。問題は、 の作者がJavaが両方のインターフェースからマージされるとは予想していなかったことです。何も呼ばないI12
I1
I2
I12
I1
I2
I12
f
I12.f
(明らかに、作成者が実際に を呼び出すコードを書いていれば、I12.f
それを販売する前に問題に気付いていただろう)。
私が実際に探しているのはこの質問に対する答えであり、変更できないコードを再構築する方法ではないことに注意してください。可能な限り最良のヒューリスティック、または存在する場合は正確な解決策を探しています。有効な例については、グレイの回答を参照してください(より堅牢なソリューションがあると確信しています)。
以下は、2 つのインターフェース内でのホモグラフィック メソッドの問題がどのように発生するかを示す具体的な例です。そして、ここに別の具体的な例があります:
次の 6 つの単純なクラス/インターフェイスがあります。それは、劇場とそこに出演するアーティストを取り巻くビジネスに似ています。簡単かつ具体的にするために、それらはすべて異なる人々によって作成されたと仮定しましょう。
Set
集合論のように集合を表す:
interface Set {
/** Complements this set,
i.e: all elements in the set are removed,
and all other elements in the universe are added. */
public void complement();
/** Remove an arbitrary element from the set */
public void remove();
public boolean empty();
}
HRDepartment
Set
従業員を表すために使用します。洗練されたプロセスを使用して、どの従業員を雇用/解雇するかを解読します。
import java.util.Random;
class HRDepartment {
private Random random = new Random();
private Set employees;
public HRDepartment(Set employees) {
this.employees = employees;
}
public void doHiringAndLayingoffProcess() {
if (random.nextBoolean())
employees.complement();
else
employees.remove();
if (employees.empty())
employees.complement();
}
}
従業員のユニバースは、Set
おそらく雇用主に応募した従業員になります。したがって、complement
そのセットで が呼び出されると、既存の従業員はすべて解雇され、以前に応募した他の従業員はすべて雇用されます。
Artist
ミュージシャンや俳優などのアーティストを表します。アーティストにはエゴがあります。この自尊心は、他の人が彼を褒めると増加する可能性があります。
interface Artist {
/** Complements the artist. Increases ego. */
public void complement();
public int getEgo();
}
Theater
パフォーマンスをArtist
行い、Artist
補完される可能性があります。劇場の観客は、公演の合間にアーティストを判断できます。パフォーマーのエゴが高ければ高いほど、聴衆は を好きになる可能性が高くなりますがArtist
、エゴが特定のポイントを超えると、アーティストは聴衆から否定的に見られます。
import java.util.Random;
public class Theater {
private Artist artist;
private Random random = new Random();
public Theater(Artist artist) {
this.artist = artist;
}
public void perform() {
if (random.nextBoolean())
artist.complement();
}
public boolean judge() {
int ego = artist.getEgo();
if (ego > 10)
return false;
return (ego - random.nextInt(15) > 0);
}
}
ArtistSet
は単純にArtist
とSet
:
/** A set of associated artists, e.g: a band. */
interface ArtistSet extends Set, Artist {
}
TheaterManager
ショーを実行します。劇場の観客がアーティストを否定的に判断した場合、劇場は人事部門に相談し、人事部門はアーティストを解雇したり、新しい人を雇ったりします。
class TheaterManager {
private Theater theater;
private HRDepartment hr;
public TheaterManager(ArtistSet artists) {
this.theater = new Theater(artists);
this.hr = new HRDepartment(artists);
}
public void runShow() {
theater.perform();
if (!theater.judge()) {
hr.doHiringAndLayingoffProcess();
}
}
}
を実装しようとすると、問題が明らかになりますArtistSet
。両方のスーパーインターフェイスcomplement
が、何か他のことを行うように指定しているためcomplement
、何らかの方法で、同じクラス内に同じシグネチャを持つ 2 つのメソッドを実装する必要があります。Artist.complement
の同形異義語ですSet.complement
。