那个网站做百科好过,wordpress删除,装饰公司网站模板,商城源码哪个品牌好最近在开发中遇到一个关于Java方法重写的一些问题#xff0c;对于方法重写的用法以及可能导致的问题产生了一些思考#xff0c;本文用于记录下这些想法。
问题场景
我们首先来看两段代码#xff1a;
Override
protected void onActivityResult(int requestCode, int resu…最近在开发中遇到一个关于Java方法重写的一些问题对于方法重写的用法以及可能导致的问题产生了一些思考本文用于记录下这些想法。
问题场景
我们首先来看两段代码
Override
protected void onActivityResult(int requestCode, int resultCode, Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);switch (requestCode){case TAKE_PHOTO_CODE:{//处理拍照得到的结果break;}case CHOOSE_FROM_ALBUM_CODE:{//处理相册选取到的结果break;}}
}Override
protected void onActivityResult(int requestCode, int resultCode, Nullable Intent data) {switch (requestCode){case TAKE_PHOTO_CODE:{//处理拍照得到的结果break;}case CHOOSE_FROM_ALBUM_CODE:{//处理相册选取到的结果break;}default:{super.onActivityResult(requestCode, resultCode, data);}}
}这两段代码是Android开发中处理Activity结果的示例。Android启动新页面后新页面设置完结果返回的时候旧页面可以从这个方法得到新页面的结果。来自不同页面的结果按照参数中的requestCode来区分这个requestCode和启动新页面时传递的对应也就是说一个requestCode标识一个页面请求和一个结果类型。例如上面示例模拟的是常见APP中换用户头像的功能结果有两种1. 拍照得到的结果2. 相册选取得到的结果。
上面两种方法就结果来说都是对的但是表达的意义不同第一种写法是纯粹地扩展父类的方法父类干的事它都干而第二种写法是改写父类的方法相当于重定义并依赖了父类的行为或者说对父类行为做了拦截、访问控制。
原本Activity类中默认实现是个空方法
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
}这种情况下两种写法的行为差异完全可以忽略不计但是实际开发中我们一般继承自FragmentActivity或AppCompatActivity这两个类都对这个方法做了相应的实现在这种情况下第一种写法父类的实现一定会被执行但是第二种写法可能将父类的实现短路了。这可能导致一些意料之外的问题比如Activity和Fragment都对某个requestCode进行处理但第二种写法会导致Fragment的对应onActivityResult方法不会被掉用。
在实际开发中我们可能会编写一个BaseActivity将一些方法实现一下并添加统计和日志那么第二种写法也可能导致日志丢失的问题。
问题分析
这个问题让我联想到一个设计原则里氏替换原则Liskov Substitution principle。这个原则说明派生类子类对象可以在程序中代替其基类超类对象。这表示程序中任何父类对象可以出现的位置子类的对象都可将其替代。进一步解读就是意味着子类可以扩展父类的功能但不能改变父类原有的功能。
这个原则考虑了安全性。编程时为了降低耦合度通常面向抽象数据类型例如接口、抽象类等来编写而父类在编写的时候也不会去考虑子类的实现那么就要求子类的实现的时候需要顾及父类的运行。
那么当我们在重写父类方法的时候情况就复杂了起来具体分为以下几种情况
当父类代码和子类代码都是同一个人负责的时候并且在代码同一项目、同一模块。这种情况比较安全因为编写子类实现的人是完全了解并掌控父类实现的当父类代码和子类代码是同一个人负责的时候而代码位于不同项目。例如一个人同时维护一个应用项目和一个独立框架。这种情况就可能出隐患因为随着项目进行这个框架中的父类可能被多个应用项目使用这个父类就可能无法兼顾多个项目的场景和用法而导致子类实现中错误地改写父类的方法。当父类代码和子类代码时不同的人负责且代码位于不同项目时这种情况就比较危险了。因为父类实现的行为实现和行为变更很可能是不透明的、未知的而且父类的实现可能不会顾及到子类的应用。那么当子类改写父类行为的时候当父类行为发生变更那么子类的实现很可能是有问题的。
方法与建议
针对上面所提到的三种情况我思考了如下三个对应的建议
针对第一种安全的情况尽量不改写父类方法在子类和父类实现中尽量补充注释和注解说明针对第二种有隐患的情况尽量不改写父类方法父类设计无法涵盖所有场景时适当时候重构父类代码而不是让子类通过“hack”的手段曲线救国。针对第三种危险的情况一定不要改写父类方法可以考虑在方法第一行就super调用。