最近牵头发起公司app的重构工做,如何经过重构让项目的耦合下降、开发效率提升,一直是我努力的方向,今天来学习一下一个注解框架Dagger2,而后看看如何使用它来下降项目的耦合。 git
一句话:一款快速的注解框架,应用于Android、Java,由 Google 开发和维护,是 Square 的 Dagger 项目的分支。github
gitHub:https://github.com/google/dagger编程
Dagger2采用依赖注入方式,依赖注入是一种面向对象的编程模式,它的出现是为了下降耦合性,所谓耦合就是类之间依赖关系,所谓下降耦合就是下降类和类之间依赖关系。设计模式
Java的面向对象编程特性,一般会在一个Java对象中引用另外一个Java对象,举例说明一下:缓存
public class ClassA { private ClassB classB; public ClassA(){ classB =new ClassB(); } public void doSomething(){ classB.doSomething(); } }
经过上面的例子能够看出,ClassA须要借助ClassB才能完成一些特定操做,可是咱们在ClassA直接实例化了ClassB,这样耦合就产生了,第一违背了单一职责原则,ClassB的实例化应该由本身完成,不该该由ClassA来完成,第二违背了开闭原则,一旦ClassB的构造函数产生变化,就须要修改ClassA的构造函数。app
经过依赖注入下降这种耦合关系:框架
1.经过构造参数传参的方式ide
public class ClassA { private ClassB classB; public ClassA(ClassB classB){ this.classB =classB; } public void doSomething(){ classB.doSomething(); } }
2.经过set方法的方式函数
public class ClassA { private ClassB classB; public ClassA(){ } public void setClassB(ClassB classB) { this.classB = classB; } public void doSomething(){ classB.doSomething(); } }
3.经过接口注入的方式学习
interface ClassBInterface { void setB(ClassB classB); } public class ClassA implements ClassBInterface { private ClassB classB; public ClassA() { } @Override public void setB(ClassB classB) { this.classB = classB; } public void doSomething() { classB.doSomething(); } }
4.经过注解注入
public class ClassA { @Inject ClassB classB; public ClassA() { } public void doSomething() { classB.doSomething(); } }
Dagger2采用的就是注解注入的方式,而后编译自动生成目标代码的方式实现宿主与被依赖者之间的关系。
在Android中的使用方式很简单:只需在Module的build.gradle中添加一下配置
dependencies { compile 'com.google.dagger:dagger:2.x' annotationProcessor 'com.google.dagger:dagger-compiler:2.x' }
Dagger2 annotation讲解
@Module 修饰的类专门用来提供依赖
@Provides 修饰的方法用在Module类里
@Inject 修饰须要依赖的地方(能够是构造方法、field或者通常的方法)
@Component 链接@Module和注入的桥梁
以项目中实际场景缓存管理为例,来体验一下解耦效果。设计遵循单一职责原则。
LCache类
/** * Created by lichaojun on 2017/3/30. * 处理缓存 */ public class LCache { private static final String DEFAULT_CACHE_NAME="LCache";//默认缓存名字 private static final int DEFAULT_MAX_CACHE_SIZE=1024;//默认缓存名字 private String cacheName=DEFAULT_CACHE_NAME;//缓存名字 private int maxCacheSize=DEFAULT_MAX_CACHE_SIZE; public LCache (){ } @Inject public LCache(String cacheName,int maxCacheSize){ this.cacheName=cacheName; this.maxCacheSize=maxCacheSize; } public void saveCache(String key ,String value){ Log.e(LCacheManager.TAG,"cacheName: = "+cacheName); Log.e(LCacheManager.TAG,"maxCacheSize: = "+maxCacheSize); Log.e(LCacheManager.TAG,"saveCache: key = "+key +" value = "+value); } public void readCache(String key){ Log.e(LCacheManager.TAG,"readCache: key: = "+key); } }
LExecutor类
public class LExecutor { private static final int DEFAULT_CPU_CORE = Runtime.getRuntime().availableProcessors();//默认线程池维护线程的最少数量 private int coreSize = DEFAULT_CPU_CORE;//线程池维护线程的最少数量 @Inject public LExecutor(int coreSize) { this.coreSize = coreSize; } public void runTask(Runnable runnable) { if (runnable == null) { return; } Log.e(LCacheManager.TAG,"coreSize: = "+coreSize); Log.e(LCacheManager.TAG, "runTask"); runnable.run(); } }
LCacheModule类
@Module public class LCacheModule { /** * 提供缓存对象 * @return 返回缓存对象 */ @Provides @Singleton LCache provideLCache() { return new LCache("lcj",500); } }
LExecutorModule类
@Module public class LExecutorModule { /** * 提供app 多任务最少维护线程个数 * @return 返回多任务最少维护线程个数 */ @Provides @Singleton LExecutor provideLExecutor() { return new LExecutor(10); } }
@Component(modules = {LCacheModule.class,LExecutorModule.class}) @Singleton public interface LCacheComponent { LCache lCache(); // app缓存 LExecutor lExecutor(); // app多任务线程池 void inject(LCacheManager lCacheManager); }
/**
* Created by lichaojun on 2017/3/30.
* 缓存处理管理
*/
public class LCacheManager {
public static final String TAG=LCacheManager.class.getSimpleName();
private LCacheComponent cacheComponent;
private static class SingletonHolder {
private static LCacheManager instance = new LCacheManager();
}
private LCacheManager(){
cacheComponent = DaggerLCacheComponent.builder().lCacheModule(new LCacheModule()).build();
cacheComponent.inject(this);
}
public static LCacheManager getInstance() {
return SingletonHolder.instance;
}
public void saveCache(final String key , final String value) {
cacheComponent.lExecutor().runTask(new Runnable() {
@Override
public void run() {
cacheComponent.lCache().saveCache(key,value);
}
});
}
public void readCache(final String key){
cacheComponent.lExecutor().runTask(new Runnable() {
@Override
public void run() {
cacheComponent.lCache().readCache(key);
}
});
}
}
LCacheManager.getInstance().saveCache("key","who is lcj ?");
看下打印结果:
经过Dagger2的方式刚开始可能会以为忽然间一个简单的事情,变得复杂了,其实没有,经过Dagger2很好的处理好了依赖关系,具体说明,好比咱们缓存LCache须要添加一个最大缓存个数变化,若是按照以前的方式,咱们首先须要对LCache进行修改,好比修改构造函数增长maxCacheSize,而后必须对LCacheManager进行修改,如今经过Dagger2的方式的话,咱们只需修改LCacheModule就能够了,LCache实例化和相关参数和LCacheManager之间并无太大的依赖关系。
基于上面的缓存处理需求,咱们须要实现读写分别使用不一样的多任务LExecutor,而且LExecutor的最小线程数为5,咱们会在LCacheComponent添加提供writeLExecutor函数,以下:
@Component(modules = {LCacheModule.class,LExecutorModule.class}) @Singleton public interface LCacheComponent { LCache lCache(); // app缓存 LExecutor lExecutor(); // app多任务线程池 LExecutor writeLExecutor(); // app 写缓存多任务线程池 void inject(LCacheManager lCacheManager); }
在LExecutorModule中添加提供依赖初始化的provideWriteLExecutor函数。以下:
@Module public class LExecutorModule { /** * 提供app 多任务最少维护线程个数 * @return 返回多任务最少维护线程个数 */ @Provides @Singleton LExecutor provideLExecutor() { return new LExecutor(10); } /** * 提供app 多任务最少维护线程个数 * @return 返回多任务最少维护线程个数 */ @Provides @Singleton LExecutor provideWriteLExecutor() { return new LExecutor(5); } }
而后写完以后Rebuild一下项目,觉得万事大吉了,结果报了以下错误,
怎么办呢,难道Dagger2就这么不堪一击吗,固然不是解决这个问题很容易,使用@Named注解解决这个问题,咱们只须要在LCacheComponent的writeLExecutor()和
LExecutorModule的provideWriteLExecutor()函数上添加相同的@Named("WriteLExecutor")便可。
对于Module的provide函数也是能够传递参数的,不过须要在当前Module中须要提供相关的参数的函数。例如:LCacheModule能够修改以下:
@Module public class LCacheModule { /** * 提供缓存对象 * @return 返回缓存对象 */ @Provides @Singleton LCache provideLCache( @Named("LCache")String name , @Named("LCache")int maxCacheSize) { return new LCache(name,maxCacheSize); } /** * 提供缓存对象 * @return 返回缓存对象 */ @Provides @Singleton @Named("LCache") String provideLCacheName() { return "lcjCache"; } /** * 提供缓存对象 * @return 返回缓存对象 */ @Provides @Singleton @Named("LCache") int provideLCacheMaxSize() { return 600; } }
这里又使用了别名@Name也是由于为了不bound multiple times错误致使编译失败,在编译的过程当中Dagger2会自动去寻找相关参数进行绑定依赖关系,这点仍是挺神奇的。
今天简单的写个例子对Dagger2有个初步的理解与认识,因为项目并无采用MVP设计模式,准备逐步采用Dagger2+MVP来下降项目中耦合。