Android Kotlin中BaseFragment放自定义Dialog的性能等影响分析
方案合理性结论
直接把仅3个Fragment用到的自定义Dialog逻辑封装进BaseFragment的做法不合理,属于基类过度设计的典型问题,不建议这么做。
各维度影响分析
- 内聚性
BaseFragment的核心职责是承载所有子类通用的基础逻辑,比如通用生命周期处理、公共状态页切换、全局权限申请适配等。把仅30%子类会用到的Dialog逻辑硬塞进去,会直接破坏基类的单一职责:一方面基类会不断堆砌非通用逻辑,逐渐变成难以维护的上帝类;另一方面Dialog本身的业务逻辑和其余7个不需要它的Fragment完全无关,无关逻辑混入公共基类后,后续修改Dialog的样式、交互逻辑时,需要侵入公共基类改代码,很容易误影响不相关页面,反而拉低了Dialog模块本身的内聚度。 - 耦合度
所有继承BaseFragment的子类,无论是否使用这个自定义Dialog,都会在编译期强依赖Dialog相关的实现代码、资源引用,后续如果要拆分模块、替换Dialog依赖库,会发现根本拆不干净耦合。另外,需要使用Dialog的3个Fragment会和基类的Dialog实现强绑定,如果后续其中某个页面需要调整Dialog的按钮逻辑、布局样式,要么得在基类加一堆兼容判断,要么就得绕开基类自己重写一套Dialog逻辑,反而回到重复写代码的原点。 - 性能
很多人觉得把Dialog放基类复用实例能省性能,实际上这点收益微乎其微,反而会带来额外开销:- 所有Fragment实例化时,都会继承基类中Dialog相关的成员变量、初始化逻辑,哪怕7个页面根本不会调用相关方法,也会平白占用内存。
- 如果基类中Dialog实例的生命周期绑定处理不当,比如提前初始化Dialog、没有在页面销毁时及时回收Dialog实例,很容易造成Context内存泄漏,带来的性能损耗远大于按需创建Dialog的开销。
- 自定义Dialog本身是轻量组件,按需创建、销毁的耗时在毫秒级,完全不会造成界面卡顿,为了这点可以忽略的性能收益牺牲架构合理性完全得不偿失。
- 架构设计
这种做法本质是滥用继承关系实现少量代码复用,违反了「组合优于继承」的基本设计原则。继承是最强的耦合关系之一,基类的任何改动都会影响所有子类,只适合承载全量通用的逻辑。为了少数几个页面的需求污染整个基类,相当于开了个坏头:后续其他开发看到基类可以放非通用逻辑,会陆续把少数页面用的Toast逻辑、埋点逻辑、下拉刷新逻辑都往BaseFragment里塞,最后基类会变成几千行的代码垃圾桶,没人敢改、没人能理清所有逻辑。
更合理的实现方案
- 独立封装Dialog管理类:单独写一个
CustomDialogController,把Dialog的创建、显示、销毁、状态恢复逻辑全封装在这个类里,哪个Fragment需要用,就在哪个Fragment里持有控制器实例,绑定对应页面的生命周期即可。既实现了Dialog逻辑的全量复用,又完全不污染公共基类,不需要用Dialog的页面不会引入任何相关依赖。 - 增加中间继承层:如果确实习惯用继承实现复用,可以在BaseFragment和业务Fragment之间加一层
BaseDialogAbilityFragment,把Dialog逻辑放在这层,需要用Dialog的3个Fragment继承这个中间类,其余7个Fragment还是直接继承原BaseFragment,把影响范围控制在真正需要相关能力的子类里。 - Kotlin扩展函数实现零侵入:如果项目用Kotlin,可以把Dialog的显示、隐藏逻辑封装成Fragment的扩展函数,不需要修改任何继承关系,哪个页面需要用直接调用扩展方法即可,灵活度最高。
内容的提问来源于stack exchange,提问作者Muhammad Ammar
相关产品推荐
相关产品推荐

