您可以将对象强制转换为未明确实现的接口吗?

时间:2019-10-15 17:46:27

标签: java android design-patterns interface

我特别想实现一种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 patternLibraryClass包装在 确实 实现Strategy的内容中界面:

public class LibraryClassProxy implements Strategy {
    private LibraryClass internal;
    public void LibraryClassProxy() {
        internal = new LibraryClass();
    }
    public void doSomething() {
        internal.doSomething();
    }
}

但是我更愿意避免这种情况-特别是因为我要扩展的类实现了 许多其他接口 ,而我宁愿不这样做必须代理每个公共方法。

3 个答案:

答案 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 {
   /* ... */
}