"ask, don't look"如何应用于Android?
How can "ask, don't look" be applied in Android?
此 Google Testing Blog post 列出了一些使代码可测试的策略。一项说部分:
Ask for things, Don't look for things (aka Dependency Injection / Law of Demeter): OK, you got rid of your new operators in you application code. But how do I get a hold of the dependencies. Simple: Just ask for all of the collaborators you need in your constructor.
换句话说,这样做:
Foo(final Bar bar) {
mBar = bar;
}
不是这个:
Foo() {
mBar = Bar.getBar(); // or new Bar();
}
这样做的原因很明显:它允许您通过向它传递一个模拟 Bar
来测试 Foo
。由于 Android 组件需要无参数构造函数,因此等效于通过额外 Bundle
.
传递它们的参数
当组件需要的东西不是Parcelable
或Serializable
时,如何在Android中应用这个原则?
我为此使用的是 Dagger2,您只依赖于对象图(或其子范围扩展子图之一)来接收所有依赖项。
大概是这样的,
- 单例
.
@Component(modules={SingletonModule.class})
@Singleton
public interface SingletonComponent {
Foo foo();
Bar bar();
void inject(MainActivity mainActivity);
}
@Module
public class SingletonModule {
@Provides
@Singleton
public Bar bar() {
return new Bar();
}
@Provides
@Singleton
public Foo foo(Bar bar) {
return new Foo(bar);
}
}
public class CustomApplication extends Application {
SingletonComponent singletonComponent;
@Override
public void onCreate() {
super.onCreate();
singletonComponent = DaggerSingletonComponent.builder()
.singletonModule(new SingletonModule())
.build();
}
public SingletonComponent getSingletonComponent() {
return singletonComponent;
}
}
public class MainActivity extends Activity {
@Inject
Foo foo;
@Inject
Bar bar;
@Override
public void onCreate(Bundle saveinstanceState) {
super.onCreate(saveinstanceState);
((CustomApplication)getApplicationContext()).getSingletonComponent().inject(this);
bar.doSomething();
foo.doSomething();
}
}
- 子范围
.
@Component(modules=SingletonModule.class)
@Singleton
public interface SingletonComponent {
Foo foo();
}
@Component(dependencies={SingletonComponent.class}, modules={MainActivityModule.class})
@ActivityScope
public interface MainActivityCompoent extends SingletonComponent {
Bar bar();
void inject(MainActivity mainActivity);
}
@Module
public class SingletonModule {
@Provides
@Singleton
public Foo foo() {
return new Foo();
}
}
@Module
public class MainActivityModule {
@Provides
@ActivityScope
public Bar bar(Foo foo) {
return new Bar(foo);
}
}
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}
public class CustomApplication extends Application {
SingletonComponent singletonComponent;
@Override
public void onCreate() {
super.onCreate();
singletonComponent = DaggerSingletonComponent.builder()
.singletonModule(new SingletonModule())
.build();
}
public SingletonComponent getSingletonComponent() {
return singletonComponent;
}
}
public class MainActivity extends Activity {
@Inject
Foo foo;
@Inject
Bar bar;
private MainActivityComponent mainActivityComponent;
@Override
public void onCreate(Bundle saveinstanceState) {
super.onCreate(saveinstanceState);
mainActivityComponent = DaggerMainActivityComponent.builder()
.singletonComponent(((CustomApplication)getApplicationContext()).getSingletonComponent())
.mainActivityModule(new MainActivityModule())
.build();
mainActivityComponent.inject(this);
bar.doSomething();
foo.doSomething();
}
}
此 Google Testing Blog post 列出了一些使代码可测试的策略。一项说部分:
Ask for things, Don't look for things (aka Dependency Injection / Law of Demeter): OK, you got rid of your new operators in you application code. But how do I get a hold of the dependencies. Simple: Just ask for all of the collaborators you need in your constructor.
换句话说,这样做:
Foo(final Bar bar) {
mBar = bar;
}
不是这个:
Foo() {
mBar = Bar.getBar(); // or new Bar();
}
这样做的原因很明显:它允许您通过向它传递一个模拟 Bar
来测试 Foo
。由于 Android 组件需要无参数构造函数,因此等效于通过额外 Bundle
.
当组件需要的东西不是Parcelable
或Serializable
时,如何在Android中应用这个原则?
我为此使用的是 Dagger2,您只依赖于对象图(或其子范围扩展子图之一)来接收所有依赖项。
大概是这样的,
- 单例
.
@Component(modules={SingletonModule.class})
@Singleton
public interface SingletonComponent {
Foo foo();
Bar bar();
void inject(MainActivity mainActivity);
}
@Module
public class SingletonModule {
@Provides
@Singleton
public Bar bar() {
return new Bar();
}
@Provides
@Singleton
public Foo foo(Bar bar) {
return new Foo(bar);
}
}
public class CustomApplication extends Application {
SingletonComponent singletonComponent;
@Override
public void onCreate() {
super.onCreate();
singletonComponent = DaggerSingletonComponent.builder()
.singletonModule(new SingletonModule())
.build();
}
public SingletonComponent getSingletonComponent() {
return singletonComponent;
}
}
public class MainActivity extends Activity {
@Inject
Foo foo;
@Inject
Bar bar;
@Override
public void onCreate(Bundle saveinstanceState) {
super.onCreate(saveinstanceState);
((CustomApplication)getApplicationContext()).getSingletonComponent().inject(this);
bar.doSomething();
foo.doSomething();
}
}
- 子范围
.
@Component(modules=SingletonModule.class)
@Singleton
public interface SingletonComponent {
Foo foo();
}
@Component(dependencies={SingletonComponent.class}, modules={MainActivityModule.class})
@ActivityScope
public interface MainActivityCompoent extends SingletonComponent {
Bar bar();
void inject(MainActivity mainActivity);
}
@Module
public class SingletonModule {
@Provides
@Singleton
public Foo foo() {
return new Foo();
}
}
@Module
public class MainActivityModule {
@Provides
@ActivityScope
public Bar bar(Foo foo) {
return new Bar(foo);
}
}
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}
public class CustomApplication extends Application {
SingletonComponent singletonComponent;
@Override
public void onCreate() {
super.onCreate();
singletonComponent = DaggerSingletonComponent.builder()
.singletonModule(new SingletonModule())
.build();
}
public SingletonComponent getSingletonComponent() {
return singletonComponent;
}
}
public class MainActivity extends Activity {
@Inject
Foo foo;
@Inject
Bar bar;
private MainActivityComponent mainActivityComponent;
@Override
public void onCreate(Bundle saveinstanceState) {
super.onCreate(saveinstanceState);
mainActivityComponent = DaggerMainActivityComponent.builder()
.singletonComponent(((CustomApplication)getApplicationContext()).getSingletonComponent())
.mainActivityModule(new MainActivityModule())
.build();
mainActivityComponent.inject(this);
bar.doSomething();
foo.doSomething();
}
}