java - 如何在Java中使用单应方法实现接口(interface)?

标签 java inheritance multiple-inheritance diamond-problem

在英语中,同形异义词对是拼写相同但含义不同的两个词。

在软件工程中,一对单应方法是两个名称相同但要求不同的方法。让我们看一个人为的例子,使问题尽可能清楚:

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.complementSet.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/

相关文章:

angularjs - AngularJS Controller 可以继承同一模块中的另一个 Controller 吗?

java - 如何在java中调用2个不同类的2个不同方法到我自己的类?

java - RecyclerView中的ImageButton

尽管代码与教程相同,但 Java Brains struts 2 项目未运行

java - 捕获异常后不终止反序列化过程

c++ - 多层上的模板化类未知类型

java - 将更改从 Bitbucket 更新到 Eclipse 中的本地 git 存储库?

c++ - C++中的接口(interface)设计和继承

c++ - 了解从多个类派生时的虚函数

java - 一个方法中的多个泛型