如何设计一个DAO类?

40

如何设计DAO类是最佳的方式?

方法1: 将DAO类设计为一个对象。

class Customer {
//customer class
}

class CustomerDAO {
  public void saveCustomer(Customer customer) {
  //code
  }

  public Customer getCustomer(int id) {
  //code
  }
}

//Client code
class client {
  public static void main(String[] args) {

   CustomerDAO customerDAO = new CustomerDAO();
   Customer customer = new Customer();
   customerDAO.saveCustomer(customer);
  }
}

方法#2:使用静态方法设计DAO类(也称为静态类)

class Customer {
//customer class
}

class CustomerDAO {
  public static void saveCustomer(Customer customer) {
  //code
  }

  public static Customer getCustomer(int id) {
  //code
  }
}

//Client code
class client {
  public static void main(String[] args) {

   Customer customer = new Customer();
   CustomerDAO.saveCustomer(customer);
  }
}
在第一种方法中,我必须在所有客户端代码中创建DAO类的对象(另一种选择是在各处传递DAO的引用)。而在第二种方法中,我不必创建对象,可以设计不具有状态跟踪的静态方法。
那么,在DAO类的设计中,哪种方法最好呢?

4
使用方法一,并使用像Spring这样的IOC容器注入引用。 - Sean Patrick Floyd
3
很奇怪没有人提到BalusC写的这篇优美而且信息量丰富的教程: DAO tutorial - the data layer。阅读它,你将会找到许多关于DAO设计和实现相关问题的答案。 - informatik01
5个回答

38

我建议采用第一种方法,但是使用Spring进行依赖注入而不是直接实例化DAO。

这样,为了对客户端代码进行单元测试,您可以替换模拟DAO并验证使用适当参数调用正确的DAO。(这里Mockito非常有用。)

如果使用静态方法,则单元测试会更加困难,因为静态方法无法被覆盖。


5
+1 我懒得自己写这个回答,但它与这个回答几乎完全一致。 - Sean Patrick Floyd
如果DAO对象中的一个客户(用户)代表当前登录的客户(用户),您会提供类似getCurrentCustomer()的方法吗?还是DAO类透明,始终通过id获取此用户? - Piotr
1
@Piotr 我认为DAO不应该关心请求的发起者是谁。 - Eric Wilson
那么你会把已登录用户的ID存储在哪里呢? 会传递到另一个地方吗?会将其存储在某个单例存储类中吗?也许您恰好知道有关已登录用户和/或用户DAO设计的任何很好的示例? - Piotr
@Piotr 如果您添加更多上下文,这将是一个适合在SO上提问的好问题。这将比对一个2.5年前的问题进行评论提供更多的可见性。 - Eric Wilson
@EricWilson,好的。很好的想法。我在这里没有看到任何关于它的问题。 - Piotr

12
为了更具抽象性:
interface IDAO<T> {

  public save(T t);
  public T getById(int id);
  //...etc

}

然后
public CustomerDao implements IDAO<Customer>{
   public save(Customer c){
        //Code here
    }
   public Customer getById(int id){
      //Code here
    }
}

将DAO从一个域名转移到另一个域名

public UniversityDao implements IDAO<University>{

     public save(University u){
       //Code here
      }
     public University getById(int id){
        //Code here
     }
}

现在,演示层或主类将包含以下代码:
IDAO  dao;
dao=new CustomerDao();
//...
dao=new UniversityDao();

6

我也会选择选项1,但我也建议你编写接口。创建一个接口来设置DAO必须提供哪些函数,然后根据需要使用不同的类来实现这些函数。

public interface CustomerDao {
    public void saveCustomer(Customer customer);

    public Customer getCustomer(int id);
}

然后您可以拥有class SimpleCustomerDao implements CustomerDAO {/*这里放代码*/}
在您的main(以及任何需要的地方),您将拥有:
//Note that you have an interface variable and a real class object 
CustomerDao customerDao = new SimpleCustomerDao();

你可以了解到这样做的好处!

如果你使用Spring或者Guice,那么确实需要使用依赖注入!


5

参考文章如何编写通用的DAO(使用Spring AOP):不要重复DAO!

您可以在您的技术栈中找到通用DAO实现的示例(只需搜索“不要重复DAO my_technology”即可)。


0

我更喜欢分层方法,这种方法告诉我们的是:

  1. 你有一个模型类 Customer
  2. 通过接口 CustomerDAO 与客户签订合同

    public interface CustomerDAO{
    
        public void saveCustomer(Customer customer);
        public Customer getCustomer(int id);
    }
    
  3. 你有一个具体的实现类,如 CustomerDAOImpl

    public class CustomerDAOImpl extends CustomerDAO{
    
        public void saveCustomer(Customer customer){
          saveCustomer(customer);
        }
    
        public Customer getCustomer(int id){
          return fetchCustomer(id);
        }
    }
    

然后编写一个管理器来管理它们,或者封装一些其他的DAO,例如:

public class ManagerImpl extends Manager{
    CustomerDAO customerDAOObj;

    // maybe you need to collect
    // all the customer related activities here in manger
    // because Client must not bother about those things.

    UserBillingDAO userBillingDAOObj; 

    public void saveCustomer(Customer customer){
      customerDAOObj.saveCustomer(customer);
    }

    public Customer getCustomer(int id){
      return customerDAOObj.fetchCustomer(id);
    }

    // Note this extra method which is defined in 
    //UserBillingDAO which I have not shown, but you are exposing 
    //this method to your Client or the Presentation layer.

     public boolean doBillingOFCustomer(id) {
        return userBillingDAOObj.doBilling(id);
    }
}

现在,表示层或主类将包含以下代码:

public static void main(String... ar){
     Manager manager = new ManagerImpl();
     manager.saveCustomer();
    // or manager.doBillingOfCustomer(); // etc
}

public void saveCustomer(Customer customer){ saveCustomer(customer); } 哈哈 + 你有像 public Customer getCustomer(int id); 这样的错误,然后是 customerDAOObj.fetchCustomer。更不用说你的格式问题了...在那之前先修复它们吧 - -1 - Mr_and_Mrs_D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接