接口隔离不止是要求,你应该要明白隔离的好处
最早我没有理解这个原则,只是以为是一种实际要求。但是后来的实践中才终于发现了隔离的好处。
==============
接口隔离的两个概念:
- 客户端不应该依赖它不需要的接口。
- 类间的依赖关系应该建立在最小的接口上。
其实这个概念我们在前几章就有接触过类似的。我是这样说的:你给我的,就是我都能用的,不要口头告诉我不要调用你这个方法。
所以到这一章,你就应该能够隐约体会到,设计模式的6大原则之间是息息相关的,并不是相互独立的。接口隔离也可以理解为单一的一种。
这里不再描述接口隔离原则了,我想说的是,通过接口实现的隔离,和隔离的好处。
何为隔离?
有四个关键字,你一定不会陌生,这就是你最早接触的隔离:
public
protected
private
default
java class 通过这三种访问权限控制类对外暴露的成员。从而实现了内部隐私属性对外部的隔离。
既然你已经开始接触设计模式了,就应该对访问权限控制已经非常熟悉,及明白使用它们的好处。这里额外介绍两点容易被忽视的:
在模块内部的类与类之间,可以尝试使用包访问权限(default,就是什么都不写)对需要交互的属性修饰。
这样的好处是:模块内部之间是稳定透明的,这时在使用getter、setter就不是那么方便了。通过包访问权限,既可以让同包内的类相互访问,又对包外(外部或上层模块)实现了隔离。
内部类调用外部类的私有属性是有访问代价的,推荐使用protected或default修饰.
而如果你有了几年的开发经验,你就会发现,在业务需求越来越复杂的环境下,访问控制权限已经不足以约束你类与类之间的关系了。
举例举例:
现在我们都喜欢按照功能去区分模块,现在我就有一个模块叫做纪念日,这个纪念日呢第一页是纪念日的列表展示页,点击添加或某个Item会进入纪念日的详情页。
那么为了解耦,我把View和业务逻辑拆开了。然后就有这么几个类了:
//纪念日的业务类,负责整个纪念日模块的管理
MemorialBusiness.java
//纪念日列表页
MemorialWindow.java
//纪念日详情页
MemorialDetaiWindwo.java
那么问题就出现啦,MemorialBusiness.java同时负责两个页面,就要有两个页面的对接方法:
- 1.取得所有数据(列表页需要)
- 2.取得纪念日详情(详情页需要)
- 3.增加纪念日(详情页需要)
对于MemorialWindow来说是不需要2和3方法的。但是它还是可以调用这两个方法,这就是一种不安全了,将来来了新同事,不太明白,调用了2或3方法不就出Bug了吗?你不能暴露给我我不需要的东西啊!
这个时候你可能也会说:列表页和详情页各弄一个Business好了。我并不想这么做,因为每个界面都弄一个对于的Business是一种碎片化,可能导致类爆炸。而只有一个Business可以对数据进行统一管理,更好维护。
那么怎么解决这个问题呢?接口隔离!
新增两个接口:
//纪念日列表页接口 只有 方法1
IMemorialListBusiness.java
//纪念日详情页接口 有 方法2 ,3
IMemorialDetalBusines.java
//业务类实现这两个接口
MemorialBusiness implements IMemorialListBusiness ,IMemorialDetalBusines
MemorialWindow 依赖接口 IMemorialListBusiness
MemorialDetaiWindwo 依赖接口 IMemorialDetalBusines
这样既实现了功能模块、数据的统一管理。又对不同页面实现了隔离操作。
回调接口,使用匿名内部类还是实现接口
最后再讲一个相关知识点:
最常见的业务场景就是按钮的事件监听和网络的异步回调。而对于回调接口通常都有两种方法实现,一种生成匿名内部类,一种是让类显示接口。哪种好呢?
看情况
情况1
如果你的类,很少或并不需要被外部模块依赖的,比如Android 的Activity,你很少看到类似这样的代码吧?
myAcitivty.hideLoading();
那么这种情况下,更建议实现接口的方式。
匿名内部类的实现会使代码变得臃肿。而实现了接口方法,可以对所有类似的事情进行统一管理。
情况2
如果你的类是需要被依赖的,比如上面的MemorialBusiness。那么这个时候你就要好好考虑下了。
需要知道:接口方法都是public的。而实现多个接口往往涉及到方法重名问题。不能向外暴露不相关的方法!!!
所以这个时候你有两种选择,
- 一种是像上文一样,通过接口进行隔离。
- 一种是通过匿名内部类隔离隐藏的回调方法。