3

我一直在尝试了解依赖注入,并且一直在取得进展,但是

我想知道这些代码的好处/区别/重要性。它们看起来相同但方法不同

//dependency injection - (as was claimed)
Customer customer = new Customer(10);

IOrderDAO orderDAO = new OrderDAO();
customer.setOrderDAO(orderDAO);
customer.getOrdersByDate();

或者

//Unknown Pattern - Please what pattern is this?
Customer customer = new Customer(10);
IOrderDAO orderDAO = new OrderDAO();
orderDAO.getOrderByDate(customer.id);

第二种方法有什么问题?

谢谢。

4

4 回答 4

3

对我来说,两者都不像依赖注入;不应该调用new.

依赖注入是由一个与所有依赖相关联的 bean 工厂完成的。它实例化 bean 并为它们提供依赖项。

我看这里根本没有豆子厂。依赖注入还有很长的路要走。

在第一个示例中,客户使用 setter 获取 OrderDAO。第一个说客户必须在其 API 中公开持久性方法。它负责保存其订单。我会说这是一个糟糕的关注点分离,因为现在客户必须了解订单。

第二个将 Customer 与 OrderDAO 分开。您将客户 ID 传递给 OrderDAO 并让它代表该客户保存订单。我认为这是一个更好的关注点分离。

但两者都不是依赖注入的好例子。

DI 的第一个也是最好的描述来自 Martin Fowler。我建议您仔细阅读以下内容:

http://martinfowler.com/articles/injection.html

它已经八岁了,但仍然存在。

于 2012-06-03T13:57:34.457 回答
3

它们都不是正确的依赖注入示例。这些都是数据访问模式的例子。

第一个是主动记录模式的一个例子。将 orderDAO 设置为客户实体的依赖项,我们可以调用属性或 setter 注入。

第二个示例可能是存储库模式。这里的依赖模式是方法注入,它转化为带有一些参数的通用调用方法(这里的参数是方法的依赖关系)。

开始学习 DI 模式的好方法是阅读这本书。还有很多在线资源,例如这些视频:

我还建议在谷歌中寻找依赖倒置原则(它与依赖注入不同)。

于 2012-06-03T15:04:43.390 回答
1

这是一个奇怪的例子,但第一个演示了依赖注入容器会做什么,第二个演示了一个对象将参数传递给另一个对象。第一个将其依赖项嵌入为调用类的实例变量;第二个是程序性质的。就其本身而言,两者都没有错。这取决于您的依赖项有多复杂以及您希望如何管理代码。

仅查看您提供的注入器代码,您并不清楚为什么要使用依赖注入。但是暂时考虑一个更复杂(也更典型)的例子。

客户服务:

public class CustomerService implements ICustomerService {
    private IOrderDAO orderDao;

    public void setOrderDAO(IOrderDAO orderDao) {
        this.orderDao = orderDao;
    }

    public Order getOrderByDate(Integer customerId, Date date) {
        return this.orderDao.findOrderByDate(customerId, date);
    }
}

OrderDAO(默认实现):

public OrderDAO implements IOrderDAO {
    private javax.sql.DataSource dataSource;

    public void setDataSource(javax.sql.DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public Order findOrderByDate(Integer customerId, Date date) {
    ...
    }
}

StubOrderDAO(存根实现):

public StubOrderDAO implements IOrderDAO {

    public Order findOrderByDate(Integer customerId, Date date) {
      return new HardCodedOrder(); // this class would extend or implement Order
    }
}

在运行时,实例CustomerService不会知道正在使用哪个 IOrderDAO 实现。这意味着您可以非常轻松地,例如,通过初始化 CustomerService 来引导一个单元测试StubOrderDAO(它总是返回一个硬编码的客户)。同样,您的 DataSource 实现可能会有所不同(模拟数据源或在不同运行时环境中不同的数据源)。

因此,用于生产用途的注射器可能如下所示:

// instantiate
CustomerService service = new CustomerService();
OrderDAO dao = new OrderDAO();
javax.sql.dataSource dataSource = jndiContext.lookup("java:comp/env/MyDataSource");

// initialize
dao.setDataSource(dataSource);
service.setOrderDAO(dao);
return service;

而使用本地(测试)数据源的注入器可能如下所示:

// instantiate
CustomerService service = new CustomerService();
OrderDAO dao = new OrderDAO();
javax.sql.dataSource dataSource = new DriverManagerDataSource("jdbc:sqlserver:yadayada...", "myUsername", "myPassword");

// initialize
dao.setDataSource(dataSource);
service.setOrderDAO(dao);
return service;

集成测试的注入器可能如下所示:

// instantiate
CustomerService service = new CustomerService();
OrderDAO dao = new StubOrderDAO();

// initialize
service.setOrderDAO(dao);
return service;

所以它本质上是一种实现良好分层和关注点分离的方法,即您访问数据库的方式独立于您访问数据以创建域模型的方式,并且两者都独立于您所做的任何聚合或业务逻辑处理in CustomerService(为简洁起见,此处未显示)。

这更有意义吗?

于 2012-06-05T19:29:24.557 回答
1

不要将控制反转与依赖注入混淆(正如另一个答案所做的那样)。我在这里描述依赖注入和 IoC:http: //www.codeproject.com/Articles/386164/Get-injected-into-the-world-of-inverted-dependenci

//dependency injection - (as was claimed)
Customer customer = new Customer(10);

IOrderDAO orderDAO = new OrderDAO();
customer.setOrderDAO(orderDAO);
customer.getOrdersByDate();

不,我不会称之为 DI。我什至会称它为写得很糟糕的代码。客户不应该意识到setOrderDAO(orderDAO)强制它存在的持久层。它打破了单一责任原则,因为客户也必须照顾订单。

//Unknown Pattern - Please what pattern is this?
Customer customer = new Customer(10);
IOrderDAO orderDAO = new OrderDAO();
orderDAO.getOrderByDate(customer.id);

customer这不是特定的模式,而是更好的代码,因为和之间没有耦合orderDao

于 2012-06-11T12:18:45.600 回答