1.2 模式不匹配
模式不匹配可以被分为几个部分,我们来逐一探讨这些问题。首先我们从一个简单的例子开始,接着,当我们逐渐完善这个例子的时候,你就会慢慢的发现这些问题了。
假设你需要设计和实现一个电子商务的程序。在这个程序中,你需要一个类来表示用户的信息,另外一个类来表示用户消费的信息,如图1.1所示。
从图中可以看出,一个用户有许多消费信息。你可以从其中的任何一个类来审视这种关系。在开始的情况下,表示这些关系的类非常的简单,
public class User{
private String username;
private String name;
private String address;
private Set billingDates;
//accessor methods (get/set pairs), business methods, etc.
}
public class BillingDetails{
private String accountNumber;
private String accountName;
private String accountType;
private User user;
//methods, get/set pairs…
}
这里我们关注的是需要持久化的实体的属性,所以在这里我们省略了一些方法诸如属性的访问以及商业逻辑等等。针对于这个例子,我们可以很容易的得到SQL的Schema,
create table USER{
USERNAME VARCHAR(15) NOT NULL PRIMARY KEY,
NAME VARCHAR(50) NOT NULL,
ADDRESS VARCHAR(100)
}
create table BILLING_DETAILS(
ACCOUNT_NUMBER VARCHAR(10) NOT NULL PRIMARY KEY,
ACCOUNT_NAME VARCHAR(50) NOT NULL,
ACCOUNT_TYPE VARCHAR(2) NOT NULL,
USERNAME VARCHAR(15) FOREIGN KEY REFERENCE USER
}
两个实体之间的关系使用外键来表示。从这个简单的对象模型可以看出,对象/关系的不匹配十分的明显;你可以直接用JDBC来完成USER和BillingDetails的插入,更新和删除。
接下来让我们考虑一个更加真实一点的例子。当我们增加更多的实体以及实体关系的时候,这种模式的不匹配就更加明显。
在我们以前的实现中,最明显的问题是我们将address作为一个String来实现的。在大多数的系统中,关于街道、城市、州、国家以及邮政编码这些信息都会被分别存储。当然,我们可以直接在User类中添加这些信息,但是这样看起来好像我们的程序象是一个关于地址信息的系统,所以更实际的做法是,我们应该创建一个独立的address类来处理这些信息。新的对象模型请参照图1.2。
我们是否需要添加一个Address表呢,这完全没有必要。通常我们可以把这些信息保存在User表中。这个设计看起来更好一些,因为我们不需要把User和Address进行额外的关联。当然最好的方法是直接创建一个SQL的类型来表示Address的信息,在User表中也只需要添加一列就能解决问题。
基本来说,我们可以添加几列或者一列(SQL类型)。这就是粒度的问题。