其他答案已经回答了您提出的问题。但是我想退后一步来了解您要使用此工厂方法完成的工作。这个工厂基本上提供了数据类型到IDataSource
参数的映射。依赖注入可能是更合适的模式,因为这是一组众所周知的数据类型和实现(如您的示例所示)。
假设您想将所有内容都存储Widgets
在 Mongo 中,但所有内容都存储Gadgets
在 Mysql 中,您可能有两个类:a MongoWidgetDataSource
that implementsIDataSource<Widget>
和 a MysqlGadgetDataSource
that implements IDataSource<Gadget>
。
我不会像在数据消费者内部那样硬编码工厂方法调用MyFactory.getDataSource(Widget.class)
,而是注入适当的IDataSource
依赖项。我们可能会对MyService
小部件(存储在 mongo 中)做一些事情。按照您的建议使用工厂将如下所示:
public class MyService {
public void doSomething() {
String value = MyFactory.getDataSource(Widget.class).getSomething();
// do something with data returned from the source
}
}
相反,您应该将适当的数据源作为构造函数 arg 注入到服务中:
public class MyService {
private final IDataSource<Widget> widgetDataSource;
public MyService(IDataSource<Widget> widgetDataSource) {
this.widgetDataSource = widgetDataSource;
}
public void doSomething() {
String value = widgetDataSource.getSomething();
// now do something with data returned from the source
}
}
这具有使您的代码更可重用和更易于单元测试(模拟依赖项)的额外好处。
然后,在您实例化的地方MyService
,您还可以连接您的数据源。许多项目使用依赖注入框架(如Guice)来使这更容易,但这不是一个严格的要求。不过,就我个人而言,我从来没有在没有任何实际规模或持续时间的项目上工作过。
如果您不使用 DI 框架,则只需在创建调用服务时实例化依赖项:
public static void main(String[] args) {
IDataSource<Widget> widgetDataSource = new MongoWidgetDataSource();
IDataSource<Gadget> gadgetDataSource = new MysqlGadgetDataSource();
MyService service = new MyService(widgetDataSource, gadgetDataSource);
service.doSomething();
}
在 Guice 中,您可以像这样连接这些数据源:
public class DataSourceModule extends AbstractModule {
@Override
protected void configure() {
bind(new TypeLiteral<IDataSource<Widget>>() {}).to(MongoWidgetDataSource.class);
bind(new TypeLiteral<IDataSource<Gadget>>() {}).to(MysqlGadgetDataSource.class);
}
}
依赖倒置是一种思考问题的不同方式,但它可以带来更加解耦、可重用和可测试的代码库。