问题
在项目拆分的过程中,一定会遇到依赖问题。有一些代码非常细节,不适合作为对外接口暴露给上层,而上层很可能需要继承自这些类。
例如,App 级别的 WebViewClient 的封装。作为业务 common 层的代码,包含了极多的业务逻辑,并不应该放到 api 包中。但是,一定存在某些特殊页面需要创建一个有特殊逻辑的 WebViewClient 的子类。
思路
继承真正做的事情有两个:
- 持有一块父类对象的内存
- 将 this 指针在必要时候(没有 override 的情况下)指向父类对象
其中,this 指针的指向有方法的和成员变量的。所以,只需要想办法完成这两个事情就好。
解决
增加一个代理层。代理层作为 api 包的一部分对外暴露。
代理通过 IOC 或者什么方法持有父类的一个实例(持有对象),并将所有方法都转调给该实例(重定向 this)。
子类不再继承自父类(子类并不能依赖到父类)而是继承自代理层。这样就完成了避免依赖复杂实现,而直接继承。
代码很简单,基本靠 IDE 自动生成即可:
public class ForwardingWebViewClient extends WebViewClient {
private WebViewClient mDelegate;
public ForwardingWebViewClient(WebViewFragment fragment) {
mDelegate = fragment.getDefaultWebViewClient();
}
...
@Override
@Deprecated
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return mDelegate.shouldOverrideUrlLoading(view, url);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view,
WebResourceRequest request) {
return mDelegate.shouldOverrideUrlLoading(view, request);
}
...
}
子类,完全把代理当成一个正常的基类来使用即可:
public class CustomWebViewClient extends ForwardingWebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view,
WebResourceRequest request) {
if (needOverride(request)) {
return true;
}
return super.shouldOverrideUrlLoading(view, request);
}
}
遗留问题
前面说过的继承的大部分功能都能够完成,唯一一个就是成员变量的this指针重定向并不能做到。如果是 kotlin 用 by 方法就可以做到了,毕竟 kotlin 的 property 也是方法。