我特别想实现一种Strategy pattern,其中一种(或多种)策略来自第三方库。
我有一个带有此类的第三方库:
public class LibraryClass {
public void doSomething() {
// ...
}
}
然后我用相同的界面创建了自己的类:
public class MyClass {
public void doSomething() {
// ...
}
}
现在在我的代码中,我想执行以下操作:
public class MainActivity extends AppCompatActivity {
public interface Strategy {
void doSomething();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
Strategy oneClass = (Strategy)(new MyClass());
Strategy twoClass = (Strategy)(new LibraryClass());
oneClass.doSomething();
twoClass.doSomething();
}
}
在这种情况下,该方法存在,因此该接口在 技术上 有效,但未明确实现。当我尝试执行此操作时,它引发了运行时错误:
java.lang.ClassCastException: MyClass cannot be cast to MainActivity$Controls
最坏的情况是,我可以使用Proxy pattern将LibraryClass
包装在 确实 实现Strategy
的内容中界面:
public class LibraryClassProxy implements Strategy {
private LibraryClass internal;
public void LibraryClassProxy() {
internal = new LibraryClass();
}
public void doSomething() {
internal.doSomething();
}
}
但是我更愿意避免这种情况-特别是因为我要扩展的类实现了 许多其他接口 ,而我宁愿不这样做必须代理每个公共方法。
答案 0 :(得分:1)
来自Java Docs:
定义新接口时,您正在定义新参考数据 类型。您可以在可以使用任何其他数据的任何地方使用接口名称 类型名称。如果您定义类型为 接口,您为其分配的任何对象必须是类的实例 实现该接口。
因此,您不能将对象强制转换为未明确实现的接口
答案 1 :(得分:1)
您想要实现的基本上是duck typing的一种形式:您有一个带有doSomething
方法的接口,并且您希望能够通过该方法传递任何东西作为该方法的实现接口,即使它没有明确指定实现接口。
您无法在Java中进行这种鸭子输入; 所有类型关系必须明确。但是通过lambda和SAM转换,您可以做得更接近 。
public class MainActivity extends AppCompatActivity {
public interface Strategy {
void doSomething();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
Strategy oneClass = new MyClass()::doSomething;
Strategy twoClass = new LibraryClass()::doSomething;
oneClass.doSomething();
twoClass.doSomething();
}
}
使用所需对象的Strategy
方法来创建新的doSomething
对象,而不是尝试进行强制转换。就个人而言,这感觉像是一个肮脏的骇客,但嘿,这就是您想要的。
答案 2 :(得分:1)
正如其他人指出的那样,在Java接口中,定义基于显式声明。我相信您所描述的情况是由Adapter设计模式而非代理覆盖的:
目的::将类的接口转换为客户期望的另一个接口。 Adapter使类可以协同工作,否则由于接口不兼容而无法实现。 -GoF页。 139
您指出的“代理”解决方案对应于Adapter模式的 object 变体。如果LibraryClass
不是最终的,则要考虑的一种选择是使用模式的 class 变体:
class MyLibraryClass extends LibraryClass implements Strategy {
/* ... */
}