"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.

传递它们的参数

当组件需要的东西不是ParcelableSerializable时,如何在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();
    }
}