依赖注入 - 这两个代码之间有什么区别?

时间:2012-06-03 13:55:04

标签: oop dependency-injection

我一直在努力了解依赖注入,但我一直在取得进展,但

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

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

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

OR

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

第二种方法有什么问题?

感谢。

4 个答案:

答案 0 :(得分:3)

两个人都不喜欢依赖注射给我;不应该拨打new

依赖注入由与所有依赖项连接的bean工厂完成。它实例化bean并为它们提供依赖关系。

我在这里看不到任何豆类工厂。这是依赖注入的漫长道路。

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

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

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

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

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

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

答案 1 :(得分:3)

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

第一个是active record pattern的示例。将orderDAO设置为客户实体的依赖关系,我们可以调用property或setter injection。

第二个例子可能是repository pattern.这里的依赖模式是方法注入,它转换为带有一些参数的公共调用方法(这里的参数是方法的依赖关系)。

开始学习DI模式的好方法是阅读this book。还有许多在线资源,例如那些视频:

我还建议在google(it's not the same as dependency injecion)中寻找依赖倒置原则。

答案 2 :(得分:1)

这是一个奇怪的例子,但第一个演示依赖注入容器将执行什么,第二个演示一个对象将参数传递给另一个对象。第一个将其依赖项作为调用类的实例变量嵌入;第二种是程序性的。本身也不是错误的。这取决于您的依赖项的复杂程度以及您希望如何管理代码。

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

的CustomerService:

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实现。这意味着您可以非常轻松地,例如,通过使用StubOrderDAO(始终返回硬编码客户)初始化来为CustomerService引导单元测试。同样,您的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;

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

这更有意义吗?

答案 3 :(得分: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);

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