MVVM框架搭建之——如何优化多层继承造成的耦合问题(一)

·  阅读 413

本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!

一、继承的优缺点

在面向对象的语言中,继承是必不可少的。继承者可以拥有父类的属性和方法,提高代码重用性。但同时继承也是侵入性的,他必须拥有父类的属性和方法从而让子类的世界多了些束缚,降低了代码的灵活性。当父类需要更改公共属性或方法时需要考虑子类的修改,特别是在缺乏规范的前提下,将会导致一堆的类要修改。

例如:在框架搭建时,开发者一般会创建一些基类,比如BaseActivity。里面可能会做些布局配置、标题设置、方法封装等基本操作,还可能会创建BaseListActivity继承BaseActivity,封装跟列表功能相关的操作。这些Base是属于最底层的依赖,换句话说也可适用于其他项目的库。

而每个项目也会有项目级的通用操作,有些开发者可能还会定义项目级的Base(例如继承BaseActivity的CommonActivity),然后在Common里面封装项目上的通用操作。此时问题就来了,是不是还得定义一个CommonListActivity以在拥有项目封装的同时拥有Base的列表功能。那么CommonListActivity应该继承CommonActivity还是BaseListActivity?还有Fragment和Dialog呢?

多层继承类图:

classDiagram
Activity <|-- BaseActivity

BaseActivity <|-- BaseListActivity
Activity: 
class BaseActivity{
+int layout
+String title
+getLayout()
}

class BaseListActivity{
+list()
}
class CommonActivity{+common}
BaseActivity <|-- CommonActivity
class CommonListActivity{+list() 
+common()}
CommonActivity <|-- "??" CommonListActivity
BaseListActivity <|-- "??" CommonListActivity

二、优化方案

通过分析不难发现,封装BaseListActivity目的就为了让页面拥有列表的相关能力,这个功能其实很独立,并不需要依赖BaseActivity里面封装的内容,此时用继承的方式只会加深页面的层级造成高耦合。如果将列表相关功能抽出,再与Activity聚合,页面依然能拥有列表能力,并且以上问题将得以解决。也就是:

  1. 不需要BaseListActivity/Fragment/Dialog存在;
  2. 列表功能对Activity隐藏细节;
  3. 列表功能的更改不会影响到具体Activity;
  4. Fragment、Dialog可同样聚合列表功能而不用都添加相同的列表相关代码;

优化后的类图:

classDiagram
class BaseActivity{
+int layout
+String title
+getLayout()
}

class ListAbility{
+list()
}

class HomeActivity{-ListAbility list}

class HomeFragment{-ListAbility list}
BaseActivity <|-- HomeActivity
HomeActivity o--ListAbility
HomeFragment o--ListAbility
HomeDialog o--ListAbility
class HomeDialog {
-ListAbility list
}

改造后列表相关功能抽到ListAbility中,页面需要列表功能时将ListAbility作为其属性,然后在合适的时机用对象调方法的方式完成。例如:list.setList(List);list.setRefresh(true); 如此是解决了高耦合的问题,但是使用的体验却不如继承来的方便。那有没既能解决耦合问题又能优化使用体验的方式呢?

三、Ability

得益于Jetpack中的Lifecycle,其他组件可以不必在Activity中也能感知到页面的生命周期,而我们所谓的封装大多也是围绕者页面的生命周期展开的,因此是不是可以利用Lifecycle的生命周期感知能力来代替需要手动操作的地方?比如在onCreate时为RecyclerView设置LayoutManager,Adapter等,在onDestroy()时做些释放操作。

Feature就利用Lifecycle做了相关尝试。Feature中定义了包含几大生命周期方法的接口IAbility

interface IAbility: LifecycleObserver {
    fun onCreate(owner: LifecycleOwner)
    fun onStart((owner: LifecycleOwner)
    fun onResume((owner: LifecycleOwner)
    fun onPause((owner: LifecycleOwner)
    fun onStop((owner: LifecycleOwner)
    fun onDestroy((owner: LifecycleOwner)
}
复制代码

Activity内部有个LifecycleRegistry,当将IAbility注册到LifecycleRegistry后,在页面生命周期发生变动时IAbility的对应生命周期方法就会收到回调。现在就可以使用IAbility大胆地做些有意思的尝试。 比如Feature中内置了几个Ability:

  • 1.BindingAbility:自动为页面绑定ViewDataBinding/DataBinding的能力;
  • 2.ListAbility/PagerAbility分别对应RecyclerView和ViewPager2的列表功能,包含数据变更感知、下拉刷新、上拉加载更多、空数据时展示空页面等能力;
  • 3.ToolbarAbility:自动为页面添加简约Toolbar的能力;
  • 4.ProgressAbility:当页面处于耗时操作时为页面展示进度弹窗,完成后关闭弹窗的能力;

值得一提的是,这些Ability都只会在注册后让页面拥有额外的能力,否则不会给页面多加一行无用代码,这是继承代替不了的。

MVVM框架搭建系列

《MVVM框架搭建之——列表页面的高效实现(二)》

《MVVM框架搭建之——简单实现不同状态的空页面(三)》

更多待续,欢迎关注。。。

分类:
Android
标签: