Java中如何将接口实例转换为子接口仅实现新增单一方法?
要把MyInterface实例转成它的子接口MyInterfacePlus实例,只需要实现新增的oneExtraMethod(空操作即可),其他方法全部委托给原MyInterface实例,还不能修改已经广泛使用的MyInterface和OtherInterface?给你几个靠谱的解决思路:
方案1:写个抽象适配器类
先搞一个抽象类,实现MyInterfacePlus,把所有MyInterface的方法都委托给传入的原实例,只留oneExtraMethod让后续实现。这样在OtherInterface的默认方法里,只需要继承这个抽象类,实现oneExtraMethod就完事,不用挨个重写所有方法。
代码示例:
// 新增这个抽象适配器类,不用碰原有接口 public abstract class MyInterfacePlusAdapter implements MyInterfacePlus { protected final MyInterface delegate; public MyInterfacePlusAdapter(MyInterface delegate) { this.delegate = delegate; } // 把MyInterface里的所有方法都按这个格式委托一遍 @Override public void methodA() { // 替换成实际的方法名和参数 delegate.methodA(); } @Override public String methodB(int param) { // 替换成实际的方法名和参数 return delegate.methodB(param); } // ... 其他MyInterface的方法都照此实现 }
然后修改OtherInterface的默认方法:
public interface OtherInterface { MyInterface getMyInterface(); default MyInterfacePlus getMyInterfacePlus() { MyInterface mi = getMyInterface(); return new MyInterfacePlusAdapter(mi) { @Override public void oneExtraMethod() { // 这里是空实现,也可以加自定义逻辑 } }; } }
这个方案好处是代码一目了然,后续复用直接用适配器就行;唯一小问题是如果以后MyInterface加新方法,得同步更新适配器,但既然MyInterface已经广泛使用,新增方法的概率应该不高。
方案2:用动态代理省掉手动委托
利用Java的动态代理机制,运行时生成MyInterfacePlus的代理实例,自动把所有MyInterface的方法委托给原实例,只单独处理oneExtraMethod。
代码示例:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public interface OtherInterface { MyInterface getMyInterface(); default MyInterfacePlus getMyInterfacePlus() { MyInterface mi = getMyInterface(); ClassLoader classLoader = MyInterfacePlus.class.getClassLoader(); Class<?>[] interfaces = {MyInterfacePlus.class}; InvocationHandler handler = (proxy, method, args) -> { // 专门处理新增的oneExtraMethod if ("oneExtraMethod".equals(method.getName()) && method.getParameterCount() == 0) { // 空操作,直接返回即可 return null; } // 其他所有方法都委托给原MyInterface实例 return method.invoke(mi, args); }; return (MyInterfacePlus) Proxy.newProxyInstance(classLoader, interfaces, handler); } }
这个方案不用手动写一堆委托方法,就算以后MyInterface加新方法也不用改代码;唯一要注意的是动态代理有一点点性能开销,不过一般场景下完全可以忽略,而且代码相对抽象一点,调试时需要留意。
方案3:给MyInterfacePlus加默认方法(仅适用于可修改它的情况)
如果MyInterfacePlus是新接口还没广泛使用,可以在它里面加默认方法,把所有MyInterface的方法都委托给一个指定的实例,然后在OtherInterface里返回的实例只需要提供这个委托实例和实现oneExtraMethod就行。
修改MyInterfacePlus:
public interface MyInterfacePlus extends MyInterface { void oneExtraMethod(); // 定义一个获取委托实例的方法 MyInterface getDelegate(); // 所有MyInterface的方法都加默认委托逻辑 @Override default void methodA() { getDelegate().methodA(); } @Override default String methodB(int param) { getDelegate().methodB(param); } // ... 其他MyInterface的方法都照此加默认实现 }
然后修改OtherInterface的默认方法:
public interface OtherInterface { MyInterface getMyInterface(); default MyInterfacePlus getMyInterfacePlus() { MyInterface mi = getMyInterface(); return new MyInterfacePlus() { @Override public MyInterface getDelegate() { return mi; } @Override public void oneExtraMethod() { // 空实现或自定义逻辑 } }; } }
这个方案不用额外写抽象类,用接口默认方法就搞定,但前提是你能修改MyInterfacePlus,如果它也已经广泛使用了,这个方案就不合适了。
内容的提问来源于stack exchange,提问作者Scott Spencer

