如何在Java中实现与单应性方法的接口? [英] How to implement interfaces with homographic methods in Java?

查看:121
本文介绍了如何在Java中实现与单应性方法的接口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In English, a homograph pair is two words that have the same spelling but different meanings.

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

In software engineering, a pair of homographic methods is two methods with the same name but different requirements. Let's see a contrived example to make the question as clear as possible:

interface I1 { 
    /** return 1 */ 
    int f()
}
interface I2 {
    /** return 2*/
    int f()
}
interface I12 extends I1, I2 {}

如何实现 I12 ? C#有办法做到这一点,但Java没有。所以唯一的方法是破解。怎么能用反射/字节码技巧/等最可靠(即它不一定是一个完美的解决方案,我只想要一个最好的解决方案)?

How can I implement I12? C# has a way to do this, but Java doesn't. So the only way around is a hack. How can it be done with reflection/bytecode tricks/etc most reliably (i.e it doesn't have to be a perfect solution, I just want the one that works the best)?

请注意,我无法合法逆向工程的一些现有的闭源大量遗留代码需要类型的参数I12 并将 I12 委托给具有 I1 作为参数的代码,并且代码为将 I2 作为参数。所以基本上我需要创建一个 I12 的实例,它知道什么时候它应该作为 I1 以及何时应该充当 I2 ,我相信可以通过查看直接调用者的运行时字节码。我们可以假设调用者没有使用反射,因为这是简单的代码。问题是 I12 的作者没想到Java会从两个接口合并 f ,所以现在我有了提出解决问题的最佳方法。没有什么叫 I12.f (显然如果作者写了一些实际上叫 I12.f 的代码,他会注意到的卖出之前的问题)。

Note that some existing closed source massive piece of legacy code which I cannot legally reverse engineer requires a parameter of type I12 and delegates the I12 both to code that has I1 as a parameter, and code that has I2 as a parameter. So basically I need to make an instance of I12 that knows when it should act as I1 and when it should act as I2, which I believe can be done by looking at the bytecode at runtime of the immediate caller. We can assume that no reflection is used by the callers, because this is straightforward code. The problem is that the author of I12 didn't expect that Java merges f from both interfaces, so now I have to come up with the best hack around the problem. Nothing calls I12.f (obviously if the author wrote some code that actually calls I12.f, he would have noticed the problem before selling it).

请注意,我实际上是在寻找这个问题的答案,而不是如何重构我无法改变的代码。我正在寻找最好的启发式方法,或者如果存在的话,可以找到精确的解决方案。请参阅Gray的答案以获得有效示例(我确信有更强大的解决方案)。

Note that I'm actually looking for an answer to this question, not how to restructure the code that I can't change. I'm looking for the best heuristic possible or an exact solution if one exists. See Gray's answer for a valid example (I'm sure there are more robust solutions).

这里是一个关于单应问题的具体例子两个接口内的方法都可能发生。这是另一个具体的例子:

Here is a concrete example of how the problem of homographic methods within two interfaces can happen. And here is another concrete example:

我有以下6个简单的类/接口。它类似于剧院周围的商业和在其中表演的艺术家。为了简单起见,我们假设它们都是由不同的人创建的。

I have the following 6 simple classes/interfaces. It resembles a business around a theater and the artists who perform in it. For simplicity and to be specific, let's assume they are all created by different people.

Set 代表一个集合,在集理论中:

Set represents a set, as in set theory:

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 使用设置来代表员工。它使用复杂的流程来解码雇用/解雇的员工:

HRDepartment uses Set to represent employees. It uses a sophisticated process to decode which employees to hire/fire:

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();
    }
}

集的世界员工可能是已向雇主申请的员工。因此,当在该集合上调用补充时,将触发所有现有员工,并且之前应用的所有其他员工都将被雇用。

The universe of a Set of employees would probably be the employees who have applied to the employer. So when complement is called on that set, all the existing employees are fired, and all the other ones that applied previously are hired.

艺术家代表艺术家,如音乐家或演员。艺术家有自我。当其他人称赞他时,这种自我会增加:

Artist represents an artist, such as a musician or an actor. An artist has an ego. This ego can increase when others compliment him:

interface Artist {
    /** Complements the artist. Increases ego. */
    public void complement();
    public int getEgo();
}

剧院制作一个艺术家执行,这可能会导致艺术家得到补充。剧院的观众可以在表演之间评判艺术家。表演者的自我越高,观众越喜欢艺术家,但如果自我超越某一点,艺术家将受到观众的负面看法:

Theater makes an Artist perform, which possibly causes the Artist to be complemented. The theater's audience can judge the artist between performances. The higher the ego of the performer, the more likely the audience will like the Artist, but if the ego goes beyond a certain point, the artist will be viewed negatively by the audience:

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 只是一个艺术家和一个 Set

/** A set of associated artists, e.g: a band. */
interface ArtistSet extends Set, Artist {
}

TheaterManager 运行节目。如果剧院的观众对艺术家负面评价,剧院会与人力资源部门进行对话,人力资源部门将反过来解雇艺术家,雇用新的艺术家等等。

TheaterManager runs the show. If the theater's audience judges the artist negatively, the theater talks to the HR department, which will in turn fire artists, hire new ones, etc:

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 在同一个类中具有相同签名的方法,不知何故。 Artist.complement Set.complement 的同形异义词。

The problem becomes clear once you try to implement an ArtistSet: both superinterfaces specify that complement should do something else, so you have to implement two complement methods with the same signature within the same class, somehow. Artist.complement is a homograph of Set.complement.

推荐答案

新想法,有点混乱......

New idea, kinda messy...

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中实现与单应性方法的接口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆