如果我有两个接口,它们的用途完全不同,但是具有相同的方法签名,那么我如何使一个类同时实现两个接口,而又不被迫编写一个同时为两个接口服务的方法并在该方法中编写一些复杂的逻辑检查调用的对象类型并调用适当代码的实现?
在C#中,这可以通过所谓的显式接口实现来克服。Java中有什么等效方法吗?
如果我有两个接口,它们的用途完全不同,但是具有相同的方法签名,那么我如何使一个类同时实现两个接口,而又不被迫编写一个同时为两个接口服务的方法并在该方法中编写一些复杂的逻辑检查调用的对象类型并调用适当代码的实现?
在C#中,这可以通过所谓的显式接口实现来克服。Java中有什么等效方法吗?
Answers:
不,没有办法在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();}
}
ISomething1 CompositeClass.asInterface1();
和ISomething2 CompositeClass.asInterface2();
方法。然后,您可以从复合类中获得一个或另一个。但是,没有很好的解决方案。
public long getCountAsLong() implements interface2.getCount {...}
[如果接口要求一个long
类但该类的用户期望的情况下int
]或private void AddStub(T newObj) implements coolectionInterface.Add
[假定collectionInterface
有一个canAdd()
方法,并且对于该类的所有实例都返回false
]之类的东西,真是令人困惑?
用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()
};
}
}
尽管它不允许从AlfaBeta
to进行强制Beta
转换,但通常来说,低调是邪恶的,并且如果可以预期Alfa
实例也经常具有Beta
某些方面,并且出于某种原因(通常是优化是唯一有效的原因),您希望能够将其转换为Beta
,你可以做一个子接口Alfa
与Beta asBeta()
它。
如果遇到此问题,则最有可能是因为您在应使用委托的地方使用了继承。如果您需要为同一基础数据模型提供两个不同的(尽管相似)接口,则应使用一个视图使用其他接口廉价地提供对数据的访问。
为了给出后一种情况的具体示例,假设您想同时实现Collection
和MyCollection
(不继承Collection
并且具有不兼容的接口)。您可以提供Collection getCollectionView()
和MyCollection getMyCollectionView()
函数,Collection
并MyCollection
使用相同的基础数据提供和的轻量级实现。
对于前一种情况...假设您确实想要一个整数数组和一个字符串数组。而不是同时从List<Integer>
和继承List<String>
,您应该具有type的一个成员和type的List<Integer>
另一个成员List<String>
,并引用这些成员,而不是尝试从这两个成员继承。即使您只需要一个整数列表,在这种情况下也最好使用组合/委托而不是继承。
“经典的” Java问题也影响了我的Android开发...
原因似乎很简单:
您必须使用更多的框架/库,更容易使事情失去控制...
就我而言,我有一个BootStrapperApp类继承自android.app.Application,
而同一类也应实现MVVM框架的Platform接口,以便进行集成。
方法冲突发生在getString()方法上,该方法由两个接口声明,并且在不同的上下文中应具有不同的实现。
解决方法(ugly..IMO)使用内部类来实现所有平台方法,只是因为一个较小的方法签名冲突...在某些情况下,甚至根本不使用这种借用的方法(但会影响主要的设计语义)。
我倾向于同意C#风格的显式上下文/命名空间指示很有帮助。
我想到的唯一解决方案是将引用对象用于要使多个接口交互的对象。
例如:假设您有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 *方法“公开”您的类
当您完全控制所有相关代码并可以预先实现时,一切都会很好。现在想象一下,您已经有一种方法在许多地方使用了现有的公共类
public class MyClass{
private String name;
MyClass(String name){
this.name = name;
}
public String getName(){
return name;
}
}
现在,您需要将其传递给现成的WizzBangProcessor,它需要类来实现WBPInterface ...,它也具有getName()方法,但是该接口希望该方法返回类型的名称,而不是您的具体实现。 Wizz Bang Processing公司。
在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接口中使用默认方法,更不用说默认覆盖了……。因为可以肯定的是,为公路车设计的每个组件都应该能够撞上飞行车并且可以正常工作-嘿它们都是汽车...我敢肯定,默认的俯仰和侧倾输入不会影响您的卫星导航的默认功能,因为汽车只会偏航!