在 Java SE 中使用 DAO 有何改进?
What is the improvement of using DAO in Java SE?
我的项目经理要我使用 DAO/DTO 对象来访问和检索数据库中的数据。项目是用 Java SE 编写的,没有使用任何框架或 ORM。他的论点是使代码更易于测试并改进代码设计。有道理吗?
初始化DAO对象怎么样?有DAO字段的class实例创建时是否应该初始化:
private PersonDao personDao = new PersonDaoImpl();
或者更确切地说是在必要时初始化?
public class A {
private PersonDao person;
public List<Person> findAll() {
person = new PersonDaoImpl();
return person.getAll();
}
}
它允许很容易地模拟这个接口,但是它是否符合 DAO 模式的使用约定?
您使用它的方式,它仍然与您的 class A 紧密耦合。
您应该使用构造函数或 setter 提供您的 DAO 作为依赖项。可能最可取的方法是使用某种控制反转(例如依赖注入框架)。
你的 class A 应该是这样的:
public class A {
private PersonDao personDao;
// possibly an @Inject annotation
public A(PersonDao personDao) {
this.personDao = personDao;
}
public List<Person> findAll() {
return personDao.getAll();
}
}
实际上,我认为这是一种反模式。这取决于您将如何使用 class A。
如果它包含不同的业务逻辑 - 很好。
如果它只是发送对 DAO 的调用(我不喜欢这个名字,也许可以使用 Repository 来代替 ;))那么它只是不必要的抽象层。
另一件事 - 你提到了 DTO。那么在这种情况下,Person class 只是一个 DTO 吗?在这里我们可以有另一个反模式。例如,如果您需要将业务对象转换为屏幕上可见的内容,DTO 就很好。或者将持久性模型与业务模型分开。
我想说的是:不要让 Person class 只是一个数据结构。给它一些行为。
DAO 模式不是 "enterprise" 模式。它主要出现在 "enterprise" 应用程序中,但您绝对可以在仅用 SE 编写的应用程序中使用。
这并不是因为您正在编写不需要测试的 SE 应用程序,所以实际上,使用 DAO 模式和 IOC 而不是在您的代码中直接使用 JDBC,您的代码将更易于测试申请。
您使用 DAO 实现 class 的方式存在问题,因为您的 class 由于 class A 与 DAO 实现之间的紧密耦合而无法正确测试.你最好使用 IOC 模式以及像 Guice 或 Dagger 这样的框架(两者都是为 SE 设计的)。
有关代码示例,请查看 slnowak 的回答。
为了最大限度地发挥可测试性和关注点分离的优势,您应该引入控制反转 (IoC) 的概念。将 IoC 应用于对象生命周期的管理时,使用术语依赖注入。这意味着您的 class A 应该完全不知道在什么时候实例化了哪个实现。
为了实现这一点,您需要一个额外的组件来 bootstrap 您的应用程序,并使用正确的实现注入所有 classes。
你可以像这样设置你的依赖接收class(setter注入,你也可以使用构造函数)
public class PersonServiceImpl implements PersonService {
private PersonDao personDao;
public List<Person> findAll() {
return personDao.getAll();
}
public setPersonDaoA(PersonDao personDao) {
this.personDao = personDao;
}
}
和一个组件来进行依赖注入:
public class ApplicationContext {
private PersonService personService;
private PersonDao personDao ;
public PersonService getPersonService() {
if (personService == null) {
personService= new PersonServiceImpl();
personService.setPersonDao(getPersonDao());
}
return personService;
}
public PersonDao getPersonDao() {
if (personDao == null) {
personDao = new PersonDaoIml();
}
return personDao ;
}
}
那么应用程序启动会涉及到:
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ApplicationContext();
PersonService personService = ctx.getPersonService();
personService.findAll();
}
}
如您所见,ApplicationContext 封装了以下知识:
- 要使用哪些实现
- 设置依赖链的顺序
- 哪些依赖已经实例化,哪些还没有实例化
PersonServiceImpl class 现在是完全可测试的,所有关于对象生命周期管理的问题都已从中提取出来。
在现实生活中,如果经常使用 Spring 或 CDI(最近越来越流行)这样的框架来完成此操作。但在你的情况下,从上面的方法开始可能是一个很好的第一步。它将获得您的项目经理提到的直接好处,而不会产生引入 Spring 的开销,也可能改变您的构建并且必须学习它是如何工作的(例如,在 XML 上下文中,源代码上下文 and/or注解)。
在稍后阶段引入 Spring 会很容易,因为所有 classes 都已经为依赖注入做好了准备。请记住,您的工厂(在我的示例中为 ApplicationContext)不应承担任何额外的责任,例如配置管理。
还要记住,上面的 ApplicationContext 示例不是单例。您自己应该确保在您的应用程序启动时只创建它的一个实例,并且所有注入都由它处理。创建重复的实例可能会导致令人困惑的错误。
数据访问对象基本上是一个对象或接口,提供对底层数据库或任何其他持久性存储的访问。
定义来自:http://en.wikipedia.org/wiki/Data_access_object
也许一个简单的例子可以帮助你理解这个概念:
假设我们有一个代表员工的实体:
public class Employee {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
员工实体将保存到数据库中相应的员工 table 中。一个简单的 DAO 接口来处理操作员工实体所需的数据库操作,如下所示:
interface EmployeeDAO {
List<Employee> findAll();
List<Employee> findById();
List<Employee> findByName();
boolean insertEmployee(Employee employee);
boolean updateEmployee(Employee employee);
boolean deleteEmployee(Employee employee);
}
接下来我们必须为该接口提供一个具体的实现来处理 SQL 服务器,另一个接口来处理平面文件等...
希望对您有所帮助
我的项目经理要我使用 DAO/DTO 对象来访问和检索数据库中的数据。项目是用 Java SE 编写的,没有使用任何框架或 ORM。他的论点是使代码更易于测试并改进代码设计。有道理吗?
初始化DAO对象怎么样?有DAO字段的class实例创建时是否应该初始化:
private PersonDao personDao = new PersonDaoImpl();
或者更确切地说是在必要时初始化?
public class A {
private PersonDao person;
public List<Person> findAll() {
person = new PersonDaoImpl();
return person.getAll();
}
}
它允许很容易地模拟这个接口,但是它是否符合 DAO 模式的使用约定?
您使用它的方式,它仍然与您的 class A 紧密耦合。
您应该使用构造函数或 setter 提供您的 DAO 作为依赖项。可能最可取的方法是使用某种控制反转(例如依赖注入框架)。
你的 class A 应该是这样的:
public class A {
private PersonDao personDao;
// possibly an @Inject annotation
public A(PersonDao personDao) {
this.personDao = personDao;
}
public List<Person> findAll() {
return personDao.getAll();
}
}
实际上,我认为这是一种反模式。这取决于您将如何使用 class A。 如果它包含不同的业务逻辑 - 很好。 如果它只是发送对 DAO 的调用(我不喜欢这个名字,也许可以使用 Repository 来代替 ;))那么它只是不必要的抽象层。
另一件事 - 你提到了 DTO。那么在这种情况下,Person class 只是一个 DTO 吗?在这里我们可以有另一个反模式。例如,如果您需要将业务对象转换为屏幕上可见的内容,DTO 就很好。或者将持久性模型与业务模型分开。
我想说的是:不要让 Person class 只是一个数据结构。给它一些行为。
DAO 模式不是 "enterprise" 模式。它主要出现在 "enterprise" 应用程序中,但您绝对可以在仅用 SE 编写的应用程序中使用。
这并不是因为您正在编写不需要测试的 SE 应用程序,所以实际上,使用 DAO 模式和 IOC 而不是在您的代码中直接使用 JDBC,您的代码将更易于测试申请。
您使用 DAO 实现 class 的方式存在问题,因为您的 class 由于 class A 与 DAO 实现之间的紧密耦合而无法正确测试.你最好使用 IOC 模式以及像 Guice 或 Dagger 这样的框架(两者都是为 SE 设计的)。
有关代码示例,请查看 slnowak 的回答。
为了最大限度地发挥可测试性和关注点分离的优势,您应该引入控制反转 (IoC) 的概念。将 IoC 应用于对象生命周期的管理时,使用术语依赖注入。这意味着您的 class A 应该完全不知道在什么时候实例化了哪个实现。
为了实现这一点,您需要一个额外的组件来 bootstrap 您的应用程序,并使用正确的实现注入所有 classes。
你可以像这样设置你的依赖接收class(setter注入,你也可以使用构造函数)
public class PersonServiceImpl implements PersonService {
private PersonDao personDao;
public List<Person> findAll() {
return personDao.getAll();
}
public setPersonDaoA(PersonDao personDao) {
this.personDao = personDao;
}
}
和一个组件来进行依赖注入:
public class ApplicationContext {
private PersonService personService;
private PersonDao personDao ;
public PersonService getPersonService() {
if (personService == null) {
personService= new PersonServiceImpl();
personService.setPersonDao(getPersonDao());
}
return personService;
}
public PersonDao getPersonDao() {
if (personDao == null) {
personDao = new PersonDaoIml();
}
return personDao ;
}
}
那么应用程序启动会涉及到:
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ApplicationContext();
PersonService personService = ctx.getPersonService();
personService.findAll();
}
}
如您所见,ApplicationContext 封装了以下知识:
- 要使用哪些实现
- 设置依赖链的顺序
- 哪些依赖已经实例化,哪些还没有实例化
PersonServiceImpl class 现在是完全可测试的,所有关于对象生命周期管理的问题都已从中提取出来。
在现实生活中,如果经常使用 Spring 或 CDI(最近越来越流行)这样的框架来完成此操作。但在你的情况下,从上面的方法开始可能是一个很好的第一步。它将获得您的项目经理提到的直接好处,而不会产生引入 Spring 的开销,也可能改变您的构建并且必须学习它是如何工作的(例如,在 XML 上下文中,源代码上下文 and/or注解)。
在稍后阶段引入 Spring 会很容易,因为所有 classes 都已经为依赖注入做好了准备。请记住,您的工厂(在我的示例中为 ApplicationContext)不应承担任何额外的责任,例如配置管理。
还要记住,上面的 ApplicationContext 示例不是单例。您自己应该确保在您的应用程序启动时只创建它的一个实例,并且所有注入都由它处理。创建重复的实例可能会导致令人困惑的错误。
数据访问对象基本上是一个对象或接口,提供对底层数据库或任何其他持久性存储的访问。
定义来自:http://en.wikipedia.org/wiki/Data_access_object
也许一个简单的例子可以帮助你理解这个概念:
假设我们有一个代表员工的实体:
public class Employee {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
员工实体将保存到数据库中相应的员工 table 中。一个简单的 DAO 接口来处理操作员工实体所需的数据库操作,如下所示:
interface EmployeeDAO {
List<Employee> findAll();
List<Employee> findById();
List<Employee> findByName();
boolean insertEmployee(Employee employee);
boolean updateEmployee(Employee employee);
boolean deleteEmployee(Employee employee);
}
接下来我们必须为该接口提供一个具体的实现来处理 SQL 服务器,另一个接口来处理平面文件等...
希望对您有所帮助