领域驱动之4层介绍

 

 (一)基本设施层,定义一些基本接口

 主要包含以下几个类和接品

1 EntityBaseclass

两个作用:

用于所有实体的基类,这样可以使用LSP;并对ID进行管理

2 IRepository<T>interface

仓储是用于持久化支持的组件。

定义四个基本方法:

T FindBy(object key);

IList<T> FindAll();

void Add(T item);

void Remove(T item);

3 IUnitOfWorkinterface

工作单元,用于对三种状态下的实体进行记录管理。定义了四个方法

void RegisterAdded(EntityBase entity, IUnitOfWorkRepository repository);

void RegisterChanged(EntityBase entity, IUnitOfWorkRepository repository);

void RegisterRemoved(EntityBase entity, IUnitOfWorkRepository repository);

void Commit();

注册方法第二个参数用于调用仓储工作单元,用于持久(实体)数据

4 UnitOfWork【类】

实现IUnitOfWork接口

使用字典维持三种状态下的实体,注册的作用,即把未添加到字典中的实体添加到各自的字典中。

Commit方法用于把三种状态下的实体保持与持久数据同步(提交到数据库);需要注意的是同步持久后,清空所有当前提交过的实体

public void Commit()

{

    using (TransactionScope scope = new TransactionScope())

    {

        foreach (EntityBase entity in this.deletedEntities.Keys)

        {

            this.deletedEntities[entity].PersistDeletedItem(entity);

        }

 

        foreach (EntityBase entity in this.addedEntities.Keys)

        {

            this.addedEntities[entity].PersistNewItem(entity);

        }

 

        foreach (EntityBase entity in this.changedEntities.Keys)

        {

            this.changedEntities[entity].PersistUpdatedItem(entity);

        }

 

        scope.Complete();

    }

 

    this.deletedEntities.Clear();

    this.addedEntities.Clear();

    this.changedEntities.Clear();

}

 

5 RepositoryBase【class】

仓储基类,实现IRepository<T>, IUnitOfWorkRepository两个接口,此类同时需要用到IUnitOfWork接口,以构造器注入方式注入UnitOfWork

 

仓储的基本功能由IRepository<T>接口定义,此类实现其中的两个方法:Add和Remove方法,因为Commit方法会调用持久接口的方法,所以Add和Remove方法并不涉及持久的相关操作。

另一方面,此基数为抽象类,对领域模型未确定,即此基类是一个泛型抽象类,所以与持久相关的查询方法:FindBy,FindAll,向下传递,这里不实现。

 

同理,对IUnitOfWorkRepository接口,实现类似模板方法。方法以保护方法向子类传递:

public virtual void PersistNewItem(EntityBase item)

{

    this.PersistNewItem((T)item);

}

protected abstract void PersistNewItem(T item);

为了子类未确定的情况下保持持久,传递的三个受保护的持久方法接受泛型入参。

 

所以此抽象基类,实现了IUnitOfWorkRepository接口,也实现了IRepository<T>接口的3个方。同时与IUnitOfWork联系起来,注入工作单元。

最终此抽象基类需要子类实现的是:

1 确定领域类型的查询相关操作

2 与持久相关的操作

protected abstract void PersistNewItem(T item);

protected abstract void PersistUpdatedItem(T item);

protected abstract void PersistDeletedItem(T item);

public abstract T FindBy(object key);

public abstract IList<T> FindAll();

 

 

 

 

 

(二)领域层,用于定义模型,模型不能使用贫血模型,需要有数据和业务

 

不能使用贫血模型(只带数据不带方法的类)。

领域模型包括数据,且有自己的业务逻辑实现

仓储层此时实体类型已经明确,所以用于实现与数据库的交互。

因为数据库类型的不同,定义了一个特定类型数据库仓储基类(做的sql数据库)

SqlRepositoryBase【class】

 

基础设施层中的RepositoryBase 有6个未实现的方法,仓储层的类型数据库基类从RepositoryBase派生

在此类中,数据库类型已经确定,但为了分层分开,为每个聚合根分别建立仓储实现,意味着在此基类中,实体类型还未确定,所以,此基类还是一个泛型类。

未实现的5个方法如下:

protected abstract void PersistNewItem(T item);

protected abstract void PersistUpdatedItem(T item);

protected abstract void PersistDeletedItem(T item);

public abstract T FindBy(object key);

public abstract IList<T> FindAll();

 

可以在此类中实现以上5个方法,数据源架构模式中有3种:

1 表数据入口

2 行数据入口

3 映射器

 

以表数据入口来看,此类实现了查询的两个方法

public override IList<T> FindAll()

{

    StringBuilder builder = new StringBuilder(50);

    builder.Append(this.baseQuery);

    builder.Append(";");

    return this.BuildEntitiesFromSql(builder.ToString());

}

其中的baseQuery在构造器中初始化,此字段由保护的抽象方法提供,此抽象方法由表数据入口中的表实现。

 

同样的,FindBy方法的sql语句也由子类提供

public override T FindBy(object key)

{

    StringBuilder builder = this.GetBaseQueryBuilder();

    builder.Append(this.BuildBaseWhereClause(key));

    return this.BuildEntityFromSql(builder.ToString());

}

 

现在没实现的是三个持久方法,它们以保护的向子类传递,但不公开。公开的是在UnitOfWork类中实现的。

 

CompanyRepository【class】

 

到这个类,数据库类型和实体类型均已经明确,所以不再需要泛型实现

此类从SqlRepositoryBase<Company>, ICompanyRepository派生

对 SqlRepositoryBase<Company>类,需要实现它的3个持久方法和对FindAll,FindBy两个方法提供的sql语句:

protected abstract override void PersistNewItem(T item);

protected abstract override void PersistUpdatedItem(T item);

protected abstract override void PersistDeletedItem(T item);

 

protected abstract string GetBaseQuery();

protected abstract string GetBaseWhereClause();

 

三个持久方法

protected override void PersistNewItem(Company item)

{

    StringBuilder builder = new StringBuilder(100);

    builder.Append(string.Format("INSERT INTO Company ({0},{1},{2},{3},{4},{5},{6}) ",

        CompanyFactory.FieldNames.CompanyId,

        CompanyFactory.FieldNames.CompanyName,

        CompanyFactory.FieldNames.CompanyShortName,

        CompanyFactory.FieldNames.Phone,

        CompanyFactory.FieldNames.Fax,

        CompanyFactory.FieldNames.Url,

        CompanyFactory.FieldNames.Remarks));

    builder.Append(string.Format("VALUES ({0},{1},{2},{3},{4},{5},{6});",

        DataHelper.GetSqlValue(item.Key),

        DataHelper.GetSqlValue(item.Name),

        DataHelper.GetSqlValue(item.Abbreviation),

        DataHelper.GetSqlValue(item.PhoneNumber),

        DataHelper.GetSqlValue(item.FaxNumber),

        DataHelper.GetSqlValue(item.Url),

        DataHelper.GetSqlValue(item.Remarks)));

 

    this.Database.ExecuteNonQuery(

        this.Database.GetSqlStringCommand(builder.ToString()));

 

    // Now do the addresses

    this.InsertAddresses(item);

}

protected override void PersistUpdatedItem(Company item)

{

    StringBuilder builder = new StringBuilder(100);

    builder.Append("UPDATE Company SET ");

 

    builder.Append(string.Format("{0} = {1}",

        CompanyFactory.FieldNames.CompanyName,

        DataHelper.GetSqlValue(item.Name)));

 

    builder.Append(string.Format(",{0} = {1}",

        CompanyFactory.FieldNames.CompanyShortName,

        DataHelper.GetSqlValue(item.Abbreviation)));

 

    builder.Append(string.Format(",{0} = {1}",

        CompanyFactory.FieldNames.Phone,

        DataHelper.GetSqlValue(item.PhoneNumber)));

 

    builder.Append(string.Format(",{0} = {1}",

        CompanyFactory.FieldNames.Fax,

        DataHelper.GetSqlValue(item.FaxNumber)));

 

    builder.Append(string.Format(",{0} = {1}",

        CompanyFactory.FieldNames.Url,

        DataHelper.GetSqlValue(item.Url)));

 

    builder.Append(string.Format(",{0} = {1}",

        CompanyFactory.FieldNames.Remarks,

        DataHelper.GetSqlValue(item.Remarks)));

 

    builder.Append(" ");

    builder.Append(this.BuildBaseWhereClause(item.Key));

 

    this.Database.ExecuteNonQuery(

        this.Database.GetSqlStringCommand(builder.ToString()));

 

    // Now do the addresses

 

    // First, delete the existing ones

    this.DeleteAddresses(item);

 

    // Now, add the current ones

    this.InsertAddresses(item);

}

 

protected override void PersistDeletedItem(Company item)

{

    // Delete the company addresses first

    this.DeleteAddresses(item);

 

    // Now delete the company

    string query = string.Format("DELETE FROM Company {0}",

        this.BuildBaseWhereClause(item.Key));

    this.Database.ExecuteNonQuery(

        this.Database.GetSqlStringCommand(query));

}

此时,与持久化相关的完成

 

构建的sql语句的两个方法:

protected override string GetBaseQuery()

{

    return "SELECT * FROM Company";

}

 

 

到此对Company实体的(领域、数据架构)构建完成。

要注意的一个是,CompanyRepository类还实现了一个接口:ICompanyRepository。当前此接口是一个空接口,可能以后会用到。。。

 

 

以上介绍,忽略了工厂,服务,测试等内容

以上代码出自:《领域驱动设计C# 2008实现》 随书源码

源码下载

上一篇:C# 成员默认访问权限(public、private、protected、internal)


下一篇:Android 开发