我有两个类,ObjectA
和ObjectB
都扩展了相同的类MasterObject
。我还有一个接口,其中包含我希望ObjectA
和ObjectB
都实现的方法。在MasterObject
中找不到此方法。然后我有一个类,它有一个MasterObject
类型的字段,并且想要访问ObjectA
和ObjectB
中的方法。没有铸造可以吗?这是我的一些代码。
此外,我无法更改MasterObject
类。
public interface MyInterface{
void doSomething();
}
class ObjectA extends MasterObject implements MyInterface {
@Override
public void doSomething(){
//...
}
}
class ObjectB extends MasterObject implements MyInterface {
@Override
public void doSomething(){
//...
}
}
class Main {
MasterObject mObj;
public void method1() {
mObj = new ObjectA();
mObj.doSomething();
}
public void method2() {
mObj = new ObjectB();
mObj.doSomething(); //runs code from ObjectB class
}
}
现在这显然引发了一些编译器问题。(无法解析方法 doSomething(((。
像这样铸造:((ObjectA) mObj).doSomething();
似乎有效,但是有没有另一种方法可以在不铸造的情况下做到这一点?有什么更干净的东西吗?
最终的解决方案是创建一个AbstractMasterObject
实现MyInterface
ObjectA
和ObjectB
具有MasterObject
和MyInterface
的完整功能AbstractMasterObject
这可以像这样完成:
public abstract class AbstractMasterObject extends MasterObject implements MyInterface{
}
然后你可以像这样声明你的对象:
AbstractMasterObject a = new ObjectA();
AbstractMasterObject b = new ObjectB();
最干净的方法是将带有接口的对象声明为类型:
MyInterface mObj;
您可以使用相同的方式使用具体类实例化对象:
mObj = new ObjectA();
...
mObj = new ObjectB();
唯一的约束是 - 没有强制转换 - 您将只能调用doSomething
方法,因为它是接口中定义的唯一方法。如果您打算仅使用此方法,则可以使用此方法。
问题是MasterObject
的类没有实现接口MyInterface
,尽管他的孩子实现了。
解决方案是实现接口:
MyInterface mObj;
mObj = new ObjectA();
你在这里有几个选项,有些已经提到过了。您已经提到无法将界面添加到MasterObject
,并且交互比doSomething
更复杂。任何其他限制都可能决定哪个最适合您。
第一种选择是按照克雷格的建议进行操作,并创建中间AbstractMasterObject
来扩展MasterObject
并实现MyInterface
。这是一种快速简便的方法,可以同时具有MasterObject
和MyInterface
实例的单个引用。缺点是Main
现在必须使用AbstractMasterObject
而不是MasterObject
.所以它不能使用MasterObject
的任何其他子类。这可能根本不是问题,也可能是一个完全的交易破坏者。实际上,它介于两者之间。
另一种选择是使用组合而不是继承。因此,ObjectA
和ObjectB
各有一个MasterObject
实例,而不是扩展它。然后他们使用该引用来访问MasterClass
行为(为简洁起见,我只是显示ObjectA
(:
class ObjectA implements MyInterface {
private masterObject masterObject;
public ObjectA(MasterObject masterObject){
this.masterObject = masterObject;
}
@Override
public void doSomething(){ /* Implementation */ }
}
从这里开始,有几种不同的策略可以将其合并到Main
。您可以在Main
中引用MasterClass
,并将其传递给ObjectA
构造函数。然后维护MasterClass
和MyInterface
引用:
class Main {
MyInterface myInterface;
MasterObject masterObject;
public void method1(){
masterObject = new MasterObject();
myInterface = new ObjectA(masterObject);
myInterface.doSomething();
masterObject.someMasterObjectMethod();
}
}
仅当ObjectA
既不重写MasterObject
方法也不访问任何受保护的成员时,此方法才有效。这也可能导致在Main
和ObjectA
中都引用同一MasterObject
的混淆。如果两个类都可以更改MasterObject
的状态,那么您最终可能会遇到一些棘手的错误。另一方面,如果这些都不是问题,那么这可能是一个好方法。它在不中断MasterObject
的情况下为Main
增加了MyInterface
,并间接使用MasterObject
来实现MyInterface
。
或者,您可以完全隐藏MasterObject
,Main
并仅通过MyInterface
进行交互。为此,您只需getMasterObject
MyInterface
即可。或者,您可以向MyInterface
添加专门与Main
如何与之交互的方法。我认为这样的方法最干净,但它涉及更改最多的代码。如果这主要是新的开发,那么可能值得努力重构。如果是较旧的代码,那么我倾向于侵入性较小的方法。
另一种选择从稍微不同的方向接近这一点。您可以完全按照定义的方式使用这些类。不同之处在于,Main
具有指向同一实例的MasterObject
和MyInterface
引用:
class Main {
private MasterObject masterObject;
private MyInterface myInterface;
public void method1(){
ObjectA objectA = new ObjectA();
masterObject = objectA; // Legal because ObjectA extends MasterObject
myInterface = objectA; // Legal because ObjectA implements MyInterface
myInterface.doSomething(); // This does ObjectA's implementation
masterObject.someMasterObjectMethod();
}
}
所以Main
,同一个实例执行MyInterface
和MasterObject
完全是巧合。我认为如果这是遗留代码,这种方法将是最好的,因为它的侵入性最小。如果这是相对较新的代码,那么我会在诉诸这样的东西之前考虑其他策略。还有其他方法,但我认为这应该是一个很好的概述。无论如何,你应该退后一步,想想这些类之间的关系到底是什么。这应该有助于为您指明正确的方向。