我一直在努力了解依赖注入,但我一直在取得进展,但
我想知道这些代码的好处/差异/重要性。它们看起来相同但不同的方法
//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);
第二种方法有什么问题?
感谢。
答案 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);
这不是特定的模式,而是更好的代码,因为customer
和orderDao
之间没有耦合。