使用hibernate的一个挑战是,manged类必须有一个默认构造函数。问题是没有明确的点来初始化类并且可以检查不变量。
如果一个类具有依赖于多个属性的不变量,则类设计变得复杂。让我们从假设的绿地设计开始:
public class A {
private int x;
private int y;
public A(int x, int y) {
this.x = x;
this.y = y;
checkInvariants(this.x, this.y);
}
private void checkInvariants(int x, int y) {
if (x + y « 0) throw new IllegalArgumentException();
}
}
这是不符合hibernate要求的基本实现。在构造函数中检查不变量。 (checkInvariants()方法的内容无关紧要,它只是为了说明类不变量可以依赖于多一个属性。)
该课程可按如下方式使用:
new A(0, 0);
new A(-1, 0); //invalid
要满足休眠要求,一种解决方法是添加私有默认构造函数和使用字段访问。 (我省略了hibernate映射。)
public class H {
int x;
int y;
public H(int x, int y) {
this.x = x;
this.y = y;
checkInvariants(this.x, this.y);
}
H(){}
private void checkInvariants(int x, int y) {
if (x + y « 0) throw new IllegalArgumentException();
}
}
这有两个主要缺点: *您开始实现依赖于客户端(Hibernate)的代码。理想情况下,一个班级不知道其来电者。 *此解决方法的一个特定问题是,如果符合不变量,则hibernate启动的实例未检查。您信任从数据库加载的数据是有问题的。即使您的应用程序是唯一使用此特定数据库模式的应用程序,管理员也可能会进行临时更改。
第二种解决方法是检查用户代码中的不变量:
public class I {
private int x;
private int y;
public I() {}
public void checkInvariants() {
if (x + y « 0) throw new IllegalArgumentException();
}
public void setX(int x){
this.x = x;
}
public void setY(int y){
this.y = y;
}
}
I i = new I();
i.setX(-1);
i.setY(0);
i.checkInvariants();
显然,这会使用户代码更复杂且容易出错。此设计无法满足实例在创建后保持一致并且在每次状态更改(方法调用)后保持一致的期望。每个用户都必须检查他创建的每个实例的不变量(可能是间接使用hibernate)。
这个问题是否有更好的解决方案:
我认为必须放松一些约束才能找到务实的解决方案。唯一的硬约束是对hibernate框架没有依赖性。 (域对象之外的Hibernate特定代码是可以的)。
(出于好奇:是否有支持“构造函数注入”的ORM框架?)
答案 0 :(得分:5)
答案 1 :(得分:3)
关系模型的连贯性 是至关重要的概念 喘气。因为固有的 数学稳定性 作为关系数据基础的原则 建模,我们可以完全自信 那个查询我们的结果 原始数据库确实会生成 真实有效的事实。 - 来自“The Art of Sql”一书 - Stephane Faroult
您的数据库应包含有效的事实或事实,您从数据库加载的数据不需要任何额外的验证,您从数据库中取出的数据应该足够好。
但如果您担心数据不好,那么我会建议存在更严重的问题。
我见过的解决方案包括一个临时数据库,其中所有数据都被清理,在进入真实数据库之前进行验证,以便在输入之前检查任何手动修复。
无论哪种方式,一旦您的数据库中的数据或虚假陈述损坏,您还可以信任什么?
答案 2 :(得分:2)
一种方法将基于您的“类I”,但是类本身第一次实际使用字段时调用checkInvariants()。这允许字段在赋值期间暂时无效(在调用setX()之后但在例如setY()之前)。但它仍然保证只使用有效数据。
您的示例类从不使用这些值,因此我假设可以通过getX(),getY()和doSomething()来访问值,例如:
public int getX(){
return x;
}
public int getY(){
return y;
}
public void doSomething(){
x = x + y;
}
你会改变它:
private boolean validated = false;
public int getX(){
if (!validated) {
checkInvariants();
}
return x;
}
public int getY(){
if (!validated) {
checkInvariants();
}
return y;
}
public void doSomething(){
if (!validated) {
checkInvariants();
}
x = x + y;
}
public void checkInvariants() {
validated = true;
if (x + y « 0) throw new IllegalArgumentException();
}
如果需要,您可以将'if(!validated)'移动到checkInvariants()中。
您可能也会查看Hibernate Validator,但它可能无法满足您的框架独立性要求。 http://docs.huihoo.com/hibernate/annotations-reference-3.2.1/validator.html