91

如果我有两个接口,它们的用途完全不同,但具有相同的方法签名,我如何让一个类同时实现这两个接口,而不会被迫编写一个用于两个接口的方法并在方法中编写一些复杂的逻辑检查正在调用哪种类型的对象并调用正确代码的实现?

在 C# 中,这可以通过所谓的显式接口实现来克服。Java中有没有等效的方法?

4

7 回答 7

77

不,没有办法在 Java 的一个类中以两种不同的方式实现相同的方法。

这可能会导致许多令人困惑的情况,这就是 Java 不允许它的原因。

interface ISomething {
    void doSomething();
}

interface ISomething2 {
    void doSomething();
}

class Impl implements ISomething, ISomething2 {
   void doSomething() {} // There can only be one implementation of this method.
}

您可以做的是从两个类组成一个类,每个类都实现不同的接口。然后,一个类将具有两个接口的行为。

class CompositeClass {
    ISomething class1;
    ISomething2 class2;
    void doSomething1(){class1.doSomething();}
    void doSomething2(){class2.doSomething();}
}
于 2010-04-08T06:38:36.067 回答
14

在 Java 中没有真正的方法可以解决这个问题。您可以使用内部类作为解决方法:

interface Alfa { void m(); }
interface Beta { void m(); }
class AlfaBeta implements Alfa {
    private int value;
    public void m() { ++value; } // Alfa.m()
    public Beta asBeta() {
        return new Beta(){
            public void m() { --value; } // Beta.m()
        };
    }
}

虽然它不允许从AlfaBetato强制转换Beta,但向下强制转换通常是邪恶的,如果可以预期一个Alfa实例通常也有一个Beta方面,并且出于某种原因(通常优化是唯一有效的原因),你希望能够要将其转换为,您可以在其中创建一个withBeta的子接口。AlfaBeta asBeta()

于 2010-04-08T14:03:04.273 回答
12

如果您遇到此问题,很可能是因为您在应该使用委托的地方使用继承。如果您需要为相同的底层数据模型提供两个不同但相似的接口,那么您应该使用视图通过其他接口廉价地提供对数据的访问。

为后一种情况举一个具体的例子,假设你想同时实现Collectionand MyCollection(它不继承自Collection并且具有不兼容的接口)。您可以使用相同的底层数据提供一个Collection getCollectionView()MyCollection getMyCollectionView()函数来提供一个轻量级的Collection和实现。MyCollection

对于前一种情况......假设你真的想要一个整数数组和一个字符串数组。而不是从两者继承List<Integer>and List<String>,您应该拥有一个 typeList<Integer>成员和另一个 type 成员List<String>,并引用这些成员,而不是尝试从两者继承。即使您只需要一个整数列表,在这种情况下最好使用组合/委托而不是继承。

于 2010-04-08T06:39:42.750 回答
1

“经典”Java问题也影响了我的Android开发......
原因似乎很简单:
你必须使用更多框架/库,更容易失控......

在我的情况下,我有一个BootStrapperApp类继承自android.app.Application
而同一个类还应该实现 MVVM 框架的Platform接口以便集成。
方法冲突发生在getString()方法上,该方法由两个接口宣布,并且在不同的上下文中应该具有不同的实现。
解决方法(丑陋..IMO)是使用内部类来实现所有平台方法,仅仅因为一个次要的方法签名冲突......在某些情况下,甚至根本不使用这种借用的方法(但影响了主要的设计语义)。
我倾向于同意 C# 风格的显式上下文/命名空间指示很有帮助。

于 2013-03-29T10:01:10.730 回答
1

我想到的唯一解决方案是使用引用对象来实现多个接口。

例如:假设您有 2 个接口要实现

public interface Framework1Interface {

    void method(Object o);
}

public interface Framework2Interface {
    void method(Object o);
}

您可以将它们包含在两个 Facador 对象中:

public class Facador1 implements Framework1Interface {

    private final ObjectToUse reference;

    public static Framework1Interface Create(ObjectToUse ref) {
        return new Facador1(ref);
    }

    private Facador1(ObjectToUse refObject) {
        this.reference = refObject;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Framework1Interface) {
            return this == obj;
        } else if (obj instanceof ObjectToUse) {
            return reference == obj;
        }
        return super.equals(obj);
    }

    @Override
    public void method(Object o) {
        reference.methodForFrameWork1(o);
    }
}

public class Facador2 implements Framework2Interface {

    private final ObjectToUse reference;

    public static Framework2Interface Create(ObjectToUse ref) {
        return new Facador2(ref);
    }

    private Facador2(ObjectToUse refObject) {
        this.reference = refObject;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Framework2Interface) {
            return this == obj;
        } else if (obj instanceof ObjectToUse) {
            return reference == obj;
        }
        return super.equals(obj);
    }

    @Override
    public void method(Object o) {
        reference.methodForFrameWork2(o);
    }
}

最后你想要的课程应该是这样的

public class ObjectToUse {

    private Framework1Interface facFramework1Interface;
    private Framework2Interface facFramework2Interface;

    public ObjectToUse() {
    }

    public Framework1Interface getAsFramework1Interface() {
        if (facFramework1Interface == null) {
            facFramework1Interface = Facador1.Create(this);
        }
        return facFramework1Interface;
    }

    public Framework2Interface getAsFramework2Interface() {
        if (facFramework2Interface == null) {
            facFramework2Interface = Facador2.Create(this);
        }
        return facFramework2Interface;
    }

    public void methodForFrameWork1(Object o) {
    }

    public void methodForFrameWork2(Object o) {
    }
}

您现在可以使用 getAs* 方法“公开”您的课程

于 2013-05-21T17:41:15.370 回答
0

您可以使用适配器模式来完成这些工作。为每个接口创建两个适配器并使用它。它应该可以解决问题。

于 2014-12-01T21:39:44.763 回答
-1

当您完全控制所有有问题的代码并且可以预先实现时,一切都很好。现在假设您有一个在许多地方使用的现有公共类,其中包含一个方法

public class MyClass{

    private String name;

    MyClass(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }
}

现在你需要将它传递到现成的 WizzBangProcessor 中,它需要类来实现 WBPInterface... 它也有一个 getName() 方法,但是这个接口不是你的具体实现,而是这个接口期望该方法返回一个类型的名称Wizz Bang 处理。

在 C# 中,这将是一件小事

public class MyClass : WBPInterface{

    private String name;

    String WBPInterface.getName(){
        return "MyWizzBangProcessor";
    }

    MyClass(String name){
        this.name = name;
    }

    public String getName(){
        return name;
    }
}

在 Java Tough 中,您将不得不识别现有已部署代码库中需要从一个接口转换为另一个接口的每个点。WizzBangProcessor 公司当然应该使用 getWizzBangProcessName(),但他们也是开发人员。在他们的上下文中 getName 很好。实际上,在 Java 之外,大多数其他基于 OO 的语言都支持这一点。Java 很少强制所有接口使用相同的方法 NAME 来实现。

大多数其他语言都有一个编译器,它非常乐意接受指令说“这个类中的这个方法与这个实现的接口中这个方法的签名相匹配就是它的实现”。毕竟,定义接口的全部意义在于允许从实现中抽象出定义。(甚至不要让我开始在 Java 中的接口中使用默认方法,更不用说默认覆盖了......因为当然,为公路汽车设计的每个组件都应该能够被撞到飞行汽车中并正常工作 - 嘿它们都是汽车...我敢肯定,说您的卫星导航的默认功能不会受到默认俯仰和滚动输入的影响,因为汽车只会偏航!

于 2017-06-29T16:09:56.417 回答