使用 Dagger 2 时,我应该将库初始化移动到哪里?
Where should I move a library initialization when using Dagger 2?
我有这段代码可以初始化 Calligraphy 默认配置。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// The initialization I want to move
CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
.setDefaultFontPath("fonts/MyFont.ttf")
.build()
);
}
}
我想在我的项目中使用 Dagger 2,但我不完全理解 类 我应该创建什么以及将此代码移到哪里才能保持项目整洁?
简而言之,你可能不会移动任何东西。这个库的问题是它使用静态方法进行初始化和使用。尝试进行依赖注入时,静态方法很痛苦。
图书馆(或者你为什么不改变任何东西)
看起来这个库是 'just' 关于通过包装上下文来切换使用的字体。因此它并没有真正为您的项目提供业务逻辑,而只是增加了您的视图/UI.
如果您希望能够进行单元测试(注入模拟)或轻松交换模块/行为,那么注入依赖项而不是仅仅调用静态方法是最有用的。在全局更改字体的情况下,两者似乎都不太可能。
另一方面,如果您确实需要(或希望)能够对其进行测试,或者只是拥有一个简洁的设计...
...包起来
静态方法很痛苦,因为你不能让对象持有逻辑。除非你把它们包起来。要使用静态方法正确执行 DI,您必须定义自己的接口。
public interface CalligraphyManager {
/**
* Called on app start up to initialize
*/
void init();
// other methods, like wrapping context for activity
Context wrap(Context context);
}
您现在有一些管理器可以访问静态方法。实现应该相当简单,因为你想做适当的 DI,init()
所需的应用程序上下文和路径将被传递到你的实现的构造函数中。因此,您的管理器的创建可以由您的 ApplicationModule
处理——只需添加一些提供方法
@Singleton
@Provides
// You would also have to provide the path from somewhere or hardcode it
// left as an exercise for the reader
CalligraphyManager provideCalligraphyManager(Context context, String path) {
return new ActualCalligraphyManager(context, path);
}
您的应用程序将如下所示:
public class MyApplication extends Application {
@Inject
CalligraphyManager mCalligraphy;
@Override
public void onCreate() {
super.onCreate();
mComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
mComponent.inject(this);
// call the initialization
mCalligraphy.init();
}
}
其他一切如常。您的应用程序组件图中有一个单例对象,因此您可以将相同的对象注入到您的活动中并在适当的地方调用“wrap”。
测试/模拟呢?
由于这样做的全部原因是为了实现它 'testable',您现在可以轻松地提供模拟/存根对象。
创建管理器的另一个实现,其中 init()
什么都不做,wrap(Context)
只是 return 相同的上下文——一个简单的存根对象。
我有这段代码可以初始化 Calligraphy 默认配置。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
// The initialization I want to move
CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
.setDefaultFontPath("fonts/MyFont.ttf")
.build()
);
}
}
我想在我的项目中使用 Dagger 2,但我不完全理解 类 我应该创建什么以及将此代码移到哪里才能保持项目整洁?
简而言之,你可能不会移动任何东西。这个库的问题是它使用静态方法进行初始化和使用。尝试进行依赖注入时,静态方法很痛苦。
图书馆(或者你为什么不改变任何东西)
看起来这个库是 'just' 关于通过包装上下文来切换使用的字体。因此它并没有真正为您的项目提供业务逻辑,而只是增加了您的视图/UI.
如果您希望能够进行单元测试(注入模拟)或轻松交换模块/行为,那么注入依赖项而不是仅仅调用静态方法是最有用的。在全局更改字体的情况下,两者似乎都不太可能。
另一方面,如果您确实需要(或希望)能够对其进行测试,或者只是拥有一个简洁的设计...
...包起来
静态方法很痛苦,因为你不能让对象持有逻辑。除非你把它们包起来。要使用静态方法正确执行 DI,您必须定义自己的接口。
public interface CalligraphyManager {
/**
* Called on app start up to initialize
*/
void init();
// other methods, like wrapping context for activity
Context wrap(Context context);
}
您现在有一些管理器可以访问静态方法。实现应该相当简单,因为你想做适当的 DI,init()
所需的应用程序上下文和路径将被传递到你的实现的构造函数中。因此,您的管理器的创建可以由您的 ApplicationModule
处理——只需添加一些提供方法
@Singleton
@Provides
// You would also have to provide the path from somewhere or hardcode it
// left as an exercise for the reader
CalligraphyManager provideCalligraphyManager(Context context, String path) {
return new ActualCalligraphyManager(context, path);
}
您的应用程序将如下所示:
public class MyApplication extends Application {
@Inject
CalligraphyManager mCalligraphy;
@Override
public void onCreate() {
super.onCreate();
mComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
mComponent.inject(this);
// call the initialization
mCalligraphy.init();
}
}
其他一切如常。您的应用程序组件图中有一个单例对象,因此您可以将相同的对象注入到您的活动中并在适当的地方调用“wrap”。
测试/模拟呢?
由于这样做的全部原因是为了实现它 'testable',您现在可以轻松地提供模拟/存根对象。
创建管理器的另一个实现,其中 init()
什么都不做,wrap(Context)
只是 return 相同的上下文——一个简单的存根对象。