在英语中,同形异义词对是拼写相同但含义不同的两个词。
在软件工程中,一对单应方法是两个名称相同但要求不同的方法。让我们看一个人为的例子,使问题尽可能清楚:
interface I1 {
/** return 1 */
int f()
}
interface I2 {
/** return 2*/
int f()
}
interface I12 extends I1, I2 {}
我该如何实现
I12
? C# has a way这样做,但 Java 没有。所以唯一的办法就是破解。如何使用反射/字节码技巧/等来完成 最可靠 (即它不必是完美的解决方案,我只想要最有效的解决方案)?请注意,一些我无法合法逆向工程的现有闭源大量遗留代码需要类型为
I12
的参数。并代表I12
都到具有 I1
的代码作为参数,以及具有 I2
的代码作为参数。所以基本上我需要做一个 I12
的实例知道什么时候应该充当 I1
以及何时应该充当 I2
,我相信可以通过 looking at the bytecode at runtime 来完成直接调用者的。我们可以假设调用者没有使用反射,因为这是简单的代码。问题是I12
的作者没想到Java合并f
从两个接口(interface),所以现在我必须想出解决这个问题的最佳方法。没有什么叫I12.f
(显然,如果作者写了一些实际调用 I12.f
的代码,他会在出售之前注意到这个问题)。请注意,我实际上是在寻找这个问题的答案,而不是如何重构我无法更改的代码。我正在寻找可能的最佳启发式方法或确切的解决方案(如果存在)。有关有效示例,请参阅 Gray 的答案(我确定有更强大的解决方案)。
Here是两个接口(interface)内单应方法问题如何发生的具体示例。这是另一个具体的例子:
我有以下 6 个简单的类/接口(interface)。它类似于围绕剧院和在其中表演的艺术家的业务。为了简单和具体起见,我们假设它们都是由不同的人创建的。
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
代表艺术家,例如音乐家或 Actor 。艺术家有自我。当别人赞美他时,这种自我会增加: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
,问题就会变得清晰。 : 两个 super 接口(interface)都指定 complement
应该做点别的,所以你必须实现两个 complement
以某种方式在同一类中具有相同签名的方法。 Artist.complement
是Set.complement
的同形异义词.
最佳答案
新想法,有点乱……
public class MyArtistSet implements ArtistSet {
public void complement() {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
// the last element in stackTraceElements is the least recent method invocation
// so we want the one near the top, probably index 1, but you might have to play
// with it to figure it out: could do something like this
boolean callCameFromHR = false;
boolean callCameFromTheatre = false;
for(int i = 0; i < 3; i++) {
if(stackTraceElements[i].getClassName().contains("Theatre")) {
callCameFromTheatre = true;
}
if(stackTraceElements[i].getClassName().contains("HRDepartment")) {
callCameFromHR = true;
}
}
if(callCameFromHR && callCameFromTheatre) {
// problem
}
else if(callCameFromHR) {
// respond one way
}
else if(callCameFromTheatre) {
// respond another way
}
else {
// it didn't come from either
}
}
}
关于java - 如何在Java中使用单应方法实现接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16494381/