如果我正确理解了这个问题,那么您已经创建了一个域模型,并且您想编写一个对象关系映射器来映射数据库中的记录和域对象。但是,您担心使用读取和写入对象字段所必需的“管道”代码污染您的域模型。
退后一步,您基本上有两种选择将数据映射代码放置在何处 - 在域类本身或外部映射类中。第一个选项通常称为 Active Record 模式,它的优点是每个对象都知道如何持久化自己,并对其内部结构有足够的访问权限,以允许它执行映射而无需暴露与业务无关的字段。
例如
public class User
{
private string name;
private AccountStatus status;
private User()
{
}
public string Name
{
get { return name; }
set { name = value; }
}
public AccountStatus Status
{
get { return status; }
}
public void Activate()
{
status = AccountStatus.Active;
}
public void Suspend()
{
status = AccountStatus.Suspended;
}
public static User GetById(int id)
{
User fetchedUser = new User();
// Lots of database and error-checking code
// omitted for clarity
// ...
fetchedUser.name = (string) reader["Name"];
fetchedUser.status = (int)reader["statusCode"] == 0 ? AccountStatus.Suspended : AccountStatus.Active;
return fetchedUser;
}
public static void Save(User user)
{
// Code to save User's internal structure to database
// ...
}
}
在此示例中,我们有一个对象,该对象表示具有名称和 AccountStatus 的用户。我们不想让 Status 直接被设置,可能是因为我们想检查更改是否是有效的状态转换,所以我们没有设置器。幸运的是,GetById 和 Save 静态方法中的映射代码可以完全访问对象的名称和状态字段。
第二个选项是有一个负责映射的第二个类。这样做的好处是将业务逻辑和持久性的不同关注点分开,这可以使您的设计更具可测试性和灵活性。这种方法的挑战是如何将名称和状态字段公开给外部类。一些选项是: 1. 使用反射(它不会对深入挖掘对象的私有部分感到不安) 2. 提供特殊命名的公共设置器(例如,在它们前面加上“Private”这个词)并希望没有人意外使用它们 3 . 如果您的语言支持它,请将设置器设置为内部但授予您的数据映射器模块访问权限。例如,在 .NET 2.0 及更高版本中使用 InternalsVisibleToAttribute 或在 C++ 中使用友元函数
有关更多信息,我推荐 Martin Fowler 的经典著作《企业架构模式》
但是,作为警告,在开始编写自己的映射器之前,我强烈建议使用 3rd-party 对象关系映射器 (ORM) 工具,例如 nHibernate 或 Microsoft 的实体框架。我参与了四个不同的项目,出于各种原因,我们编写了自己的映射器,很容易浪费大量时间维护和扩展映射器,而不是编写为最终用户提供价值的代码。到目前为止,我已经在一个项目中使用了 nHibernate,虽然它最初的学习曲线相当陡峭,但您在早期投入的投资获得了可观的回报。