概述
首先说明,AOP和IOC不是Android特有的概念,在其它许多框架、领域都有它们的影子,比如说Spring后台开发中,也有AOP和IOC的思想。在Android中实现这些的方式有:动态代理,APT,AspectJ,Transform&Javassist(或者Gradle编译期间的许多节点都可以)等。
AOP
AOP(Aspect Oriented Programming):面向切面编程。
AOP和OOP一样,是一种程序设计思想。AOP的目标就是分离关注点(你要做的事,就是关注点),它旨在将关注点与业务主体进行分类,从而提高程序代码的模块化程度,关注点是一个抽象的概念,它是指那些在项目中贯穿多个模块的业务,比如说日志,埋点等。
非侵入式的优点:代码可复用,方便移植。非侵入式也体现了代码的设计原则:高内聚,低耦合,要添加新功能不需要改动之前的代码。
借用网上一个通俗的解释:假如你是个公子哥,没啥人生目标,天天就是衣来伸手,饭来张口,整天只知道玩一件事!那么,每天你一睁眼,就光想着吃完饭就去玩(你必须要做的事),但是在玩之前,你还需要穿衣服、穿鞋子、叠好被子、做饭等等等等事情,这些事情就是你的关注点,但是你只想吃饭然后玩,那么怎么办呢?这些事情通通交给别人去干。在你走到饭桌之前,有一个专门的仆人A帮你穿衣服,仆人B帮你穿鞋子,仆人C帮你叠好被子,仆人C帮你做饭,然后你就开始吃饭、去玩(这就是你一天的正事),你干完你的正事之后,回来,然后一系列仆人又开始帮你干这个干那个,然后一天就结束了!
AOP的好处就是你只需要干你的正事,其它事情别人帮你干。也许有一天,你想裸奔,不想穿衣服,那么你把仆人A解雇就是了!也许有一天,出门之前你还想带点钱,那么你再雇一个仆人D专门帮你干取钱的活!这就是AOP。每个人各司其职,灵活组合,达到一种可配置的、可插拔的程序结构。
IOC/DI
IOC(Inverse of Control):控制反转,也可以称为依赖倒置(DI-Dependency Injection)。
- 依赖:从程序的角度看,就是比如A要调用B的方法,那么A就依赖于B。
- 倒置:因为A必须要有B,才可以调用B,如果不倒置,就需要A主动获取B的实例(即new)。所以,不倒置,意味着A要主动获取B,才能使用B。倒置就是A要调用B的话,A并不需要主动获取B,而是由其它人自动将B送上门来。
依旧借用网上一个形象的举例:通常情况下,假如你有一天在家里口渴了,要喝水,那么你可以到你小区的小卖部去,告诉他们,你需要一瓶水,然后小卖部给你一瓶水!这本来没有太大问题,关键是如果小卖部很远,那么你必须知道:从你家如何到小卖部;小卖部里是否有你需要的水;你还要考虑是否开着车去;等等等等,也许有太多的问题要考虑了。也就是说,为了一瓶水,你还可能需要依赖于车等等这些交通工具或别的工具,问题是不是变得复杂了?那么如何解决这个问题呢?
解决这个问题的方法很简单:小卖部提供送货上门服务,凡是小卖部的会员,你只要告知小卖部你需要什么,小卖部将主动把货物给你送上门来!这样一来,你只需要做两件事情,你就可以活得更加轻松自在:
- 第一:向小卖部注册为会员。
- 第二:告诉小卖部你需要什么。
动态代理
见动态代理。
APT
APT(Annotation Processing Tool)是一种编译期注解处理技术。它通过定义注解和处理器来实现编译期生成代码的功能,并且将生成的代码和源代码一起编译成.class文件。
见Java注解。
AspectJ
AspectJ就是一种编译器,它在Java编译器的基础上增加了关键字识别和编译方法。因此,AspectJ可以编译Java代码。它还提供了Aspect程序。在编译期间,将开发者编写的Aspect程序织入到目标程序中,扩展目标程序的功能。开发者可以通过编写AspectJ程序实现AOP功能。
见AspectJ。
Transform&Javassist
Transform是Android Gradle提供的,可以操作字节码的一种方式。App编译时,源代码首先会被编译成class,然后再被编译成dex。在class编译成dex的过程中,会经过一系列Transform处理。
Javassist是一个能够非常方便操作字节码的库。我们通过它们可以修改编译的.class文件。利用这种方式,我们将横切关注点封装到Transform,来达到与业务主体分离的目的。
总结
利用AOP和IOC可以做一些很有意思的事情,一些知名的开源框架都采用了它们的思想。例如:ButterKnife、Retrofit、Hugo、Dagger2等。另外,它们还可以用在性能检测、权限管理和埋点技术上。