泛型和字段如何协助独立 Java 应用程序中的 DAO 模式

Posted

技术标签:

【中文标题】泛型和字段如何协助独立 Java 应用程序中的 DAO 模式【英文标题】:How do Generics and Fields assist DAO Pattern in Standalone Java applications 【发布时间】:2013-03-28 13:15:04 【问题描述】:
//Interface DAO

    public abstract class BaseDAO<T extends BaseDTO> 


    public void update(T t) throws DBException 
     Field[] fieldsToInsert = t.getClass().getDeclaredFields();
    //code to update database object academic or event
    

     public Integer create(T t) throws DBException 
      Field[] fieldsToInsert = t.getClass().getDeclaredFields();
    //code to create academic or event in database
    

 



//Concrete DAOs
public class AcademicDAO extends BaseDAO<AcademicDTO> 
//provide implementation


public class EventDAO extends BaseDAO<EventDTO> 
//provide implementation




//Transfer object
public class AcademicDTO extends BaseDTO 
   String title;
   String surname;
   //getters and setters



public class BaseDTO 

    protected Integer ID;

    public Integer getID() 
        return ID;
    

    public void setID(Integer ID) 
        this.ID = ID;
    

大家好,我有一个示例代码,它遵循上述结构来创建一个小型 Java 应用程序来管理学术和活动。宽大处理这个pattern

1- 你们专家比我更熟悉这种模式。我想了解为什么在这种情况下使用泛型,以便 DAO 可以扩展和实现泛型基类。如果能用一个例子来说明泛型在这里的优势是多么的好,那就太好了。

2 - 我也见证了 java Fields 的使用。泛型和字段之间有联系吗?

我想在学术报告中记录 DAO 模式,但我发现很难理解 GenericsReflect Field 如何在其中发挥作用。它们是否支持灵活性和松散耦合?

【问题讨论】:

【参考方案1】:

您提供的代码是一组可重用的逻辑,用于加载和持久化实体。很多时候,在一个非平凡大小的应用程序中,您最终会持久化许多不同类型的对象。在此示例中,您可以根据需要定义任意数量的对象,但只定义实际保存和加载一次的逻辑。通过询问 DTO 那里有哪些 Field 对象,它可以获取数据以帮助构建用于加载和保存的查询。

泛型允许您在保持类型安全的同时使用此模式。 AcademicDAO 只能处理AcadmeicDTO。您不能使用AcademicDAO 来存储EventDTO。泛型允许类的实例在处理Field 对象时依赖更具体的类型。如果您没有泛型,BaseDAO 将采用Object,并且您将无法访问除 Object 提供的方法之外的任何方法,因为 JVM 不知道提供了什么类,所以它必须将其知识限制为Object。使用getClass().getDeclaredFields() 绕过了该限制,因为getClass() 返回Object 参数的实际类。

Field 只是一种使用反射来访问每个 DTO 中属性值的方法。如果您必须使用getTitle() 直接访问这些字段,您将无法重用通用基类来进行持久化。当您需要访问 EventDTO 时会发生什么?您必须为此提供逻辑。 Field 允许您跳过该逻辑。

编辑:

为了解释访问getID 的意思,您可以在BaseDAO 内执行以下操作,因为已知TBaseDTO 并定义了getID() 方法:

public abstract class BaseDAO<T extends BaseDTO> 

    public boolean update(T t) throws DBException 
        Integer id = t.getID();
        Field[] fields = t.getClass().getDeclaredFields();
        // Assuming you have a db object to execute queries using bind variables:
        boolean success = db.execute("UPDATE table SET ... WHERE id = ?", id.intValue());
        return success;
    

如果你有这个(在非泛型类中):

public boolean update(Object o) throws DBException 
    // This line doesn't work, since Object doesn't have a getID() method.
    Integer id = t.getID();
    Field[] fields = o.getClass().getDeclaredFields();

    boolean success = db.execute("UPDATE table SET ... WHERE id = ?", id.intValue());
    return success;

您必须查看那些 Field 对象,或者询问 ID 字段并假设它存在。

【讨论】:

这个解释很清楚,也很容易理解。非常感谢。 请详细说明以下行:如果您没有泛型,BaseDAO 将采用 Object,并且您将无法访问除 Object 提供的字段之外的任何字段,因为 JVM 不会'不知道提供了什么类,所以它必须将它的知识限制为对象的知识 其实那部分是不正确的。 getClass() 调用返回实际类型,getDeclaredFields() 然后返回在该类型上声明的所有字段,但不返回其继承的字段。我会相应地更新我的答案。 Steve this part “如果你没有泛型,BaseDAO 将采用 Object,并且你将无法访问除 Object 提供的方法之外的任何方法,因为 JVM 不知道什么提供了类,因此它必须将其知识限制为对象的知识。”我不清楚。我了解 getclass() 等的作用,但是如果我们在 BaseDao 方面不使用泛型怎么办,您的回答会令人困惑。 JVM 只能使用已声明的类型。如果我有一个方法save(Object o),并且我传入了一个BaseDTO,那么该方法就无法访问BaseDTO 上的getID() 方法。输入参数是一个Object,它没有定义getID()。这有帮助吗?【参考方案2】:

对于问题 1。使用泛型允许使用 updatecreate 的相同实现,而不管 DTO 的类型如何。考虑一下你是否没有使用泛型。那么你可以为update 的参数类型做的最好的事情就是BaseDTO,但是你可以调用

academicDAO.update( eventDTO )

这没有意义。使用您拥有的代码,这将是一个类型错误。所以主要优点是:更好的类型检查。

对于问题 2。使用字段允许 updatecreate 的单个实现处理各种具体类型的 DTO 对象。

【讨论】:

以上是关于泛型和字段如何协助独立 Java 应用程序中的 DAO 模式的主要内容,如果未能解决你的问题,请参考以下文章

java里的泛型和通配符

java笔记Java中的泛型和类通配符

持有对象——Java中的容器

UML 与泛型和可为空字段的关系

java泛型和通配符

总结java的泛型和内部类