泛型和字段如何协助独立 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 模式,但我发现很难理解 Generics 和 Reflect 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
内执行以下操作,因为已知T
是BaseDTO
并定义了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。使用泛型允许使用 update
和 create
的相同实现,而不管 DTO 的类型如何。考虑一下你是否没有使用泛型。那么你可以为update
的参数类型做的最好的事情就是BaseDTO
,但是你可以调用
academicDAO.update( eventDTO )
这没有意义。使用您拥有的代码,这将是一个类型错误。所以主要优点是:更好的类型检查。
对于问题 2。使用字段允许 update
和 create
的单个实现处理各种具体类型的 DTO 对象。
【讨论】:
以上是关于泛型和字段如何协助独立 Java 应用程序中的 DAO 模式的主要内容,如果未能解决你的问题,请参考以下文章