zoukankan      html  css  js  c++  java
  • 掀起你的盖头来:Unit Of Work-工作单元

    写在前面

    阅读目录:

    掀起了你的盖头来,让我看你的眼睛,你的眼睛明又亮呀,好像那水波一模样;掀起了你的盖头来,让我看你的脸儿,看看你的脸儿红又圆呀,好像那苹果到秋天。。。

      Hi,Unit Of Work,掀起你的盖头来,原来 You are so beautiful !

    概念中的理解

    Unit Of Work:维护受业务事务影响的对象列表,并协调变化的写入和并发问题的解决。即管理对象的CRUD操作,以及相应的事务与并发问题等。Unit of Work是用来解决领域模型存储和变更工作,而这些数据层业务并不属于领域模型本身具有的。

      关于Unit Of Work的更多详情,请查看:http://martinfowler.com/eaaCatalog/unitOfWork.htmlUnit Of Work中的“Unit”是单元的意思,知道单元测试的朋友都知道其也包含“Unit”单词,但是是一个意思吗?Unit Test(单元测试)虽然也包含“Unit”这个单词,但是意义并不是一样,单元测试中的“Unit”可以看做是最小单元,比如组装飞机的最小零部件,但是Unit Of Work(工作单元)并非无此,注意后面“Work”单词,意思是可以“工作”的单元,比如一场篮球比赛需要两个队,10名上场球员参与,这样完成的“动作”才会称之为篮球比赛,也就是“工作单元”,一个篮球队或是一个篮球队员并不能完成称为篮球比赛,但是这个工作的"单元"也只是相对而言,比如上篮动作就只需要一个篮球队员就可以完成,那这个篮球队员就可以看做是“工作单元”。需要注意的是,Unit中可以包含很多“动作”,可以是一个也可以是多个,比如上面的例子,如果“单元”中包含对于多个动作,那这个“单元”中所有的动作都是“内聚”的,脱离这个“单元”这个动作就没有意义了,比如篮球比赛中的一次吹罚,当然这只是字面上理解的意思,也只是我个人的一些看法,希望看到着没有被我忽悠到。

      扯了一些不沾边的东西,我们再看一个现实中例子,也最能说明Unit Of Work所包含的意思,就是银行转账操作,包含两个动作:转出方扣钱和转入方加钱,这两个动作要么都完成,要么都不完成,也就是事务操作,完成就Commit(提交),完不成就Rollback(回滚)。

      回到Unit Of Work的定义,Unit of Work是用来解决领域模型存储和变更工作,在ORM进行持久化的时候,比如Entity Framework的SaveChanges操作,其实就可以看做是Unit Of Work,也就是定义中所说“用来解决领域模型存储和变更工作”,但是如果项目是基于Entity Framework进行DDD(领域驱动设计)开发设计的,那Entity Framework中的Domain Model就必然包含业务逻辑,这就不符合“而这些数据层业务并不属于领域模型本身具有的”,也就是说Unit Of Work必须独立于Domain Layer(领域层),注意独立的业务是“数据层”业务,并不是业务场景中的“业务”,比如“转账业务”,转出方扣钱和转入方加钱这个业务就属于“数据层业务”,有的人会把Unit Of Work放在Domain Layer(领域层)中,其实是有些不恰当的,应该是放在Infrastructure Layer(基础层)中,但其实也只是相对而言,如果涉及到具体的业务单元模块,具体实现可以放在领域层中。

      在DDD(领域驱动设计)开发设计中,Unit Of Work的使用一般会结合Repository(仓储)使用,有关Repository可以参阅dudu的一篇文章:http://www.cnblogs.com/dudu/archive/2011/05/25/repository_pattern.html,文中的解释很清楚直白:

    Repository:是一个独立的层,介于领域层与数据映射层(数据访问层)之间。它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接口提供给领域层进行领域对象的访问。Repository是仓库管理员,领域层需要什么东西只需告诉仓库管理员,由仓库管理员把东西拿给它,并不需要知道东西实际放在哪。

      Unit Of Work所做的工作可以看做是收集Repository出入库的“商品”,便于一次装车,运输过程中如果没有出现问题,那这车的所有“商品”就安全到达,如果出现问题,那这车的所有“商品”全部打回,这辆车就是“单元”的意思。

      关于Repository和Unit Of Work的关系,简单画了个示意图:

                    点击查看大图

    代码中的实现

      关于Unit Of Work项目中的应用,可以参照dax.net的Byteart Retail项目,本人现在也正在学习中,项目是基于DDD设计实现的,下面是IUnitOfWork的示例代码:

     1 namespace ByteartRetail.Domain
     2 {
     3     /// <summary>
     4     /// 表示所有集成于该接口的类型都是Unit Of Work的一种实现。
     5     /// </summary>
     6     /// <remarks>有关Unit Of Work的详细信息,请参见UnitOfWork模式:http://martinfowler.com/eaaCatalog/unitOfWork.html 7     /// </remarks>
     8     public interface IUnitOfWork
     9     {
    10         /// <summary>
    11         /// 获得一个<see cref="System.Boolean"/>值,该值表述了当前的Unit Of Work事务是否已被提交。
    12         /// </summary>
    13         bool Committed { get; }
    14         /// <summary>
    15         /// 提交当前的Unit Of Work事务。
    16         /// </summary>
    17         void Commit();
    18         /// <summary>
    19         /// 回滚当前的Unit Of Work事务。
    20         /// </summary>
    21         void Rollback();
    22     }
    23 }

      根据UnitOfWork中的概念描述“这些数据层业务并不属于领域模型本身具有的”,所以IUnitOfWork放在Infrastructure Layer(基础设施层),其实IUnitOfWork的具体管理实现是放在领域层的,但不会放在Domain Model(领域模型)中,具体的数据层业务会结合Repository,也就是说IUnitOfWork会贯彻所有的Repository实现,因为它要对所有仓储的的持久化做统一管理:

     1     /// <summary>
     2     /// Represents that the implemented classes are repository contexts.
     3     /// </summary>
     4     public interface IRepositoryContext : IUnitOfWork, IDisposable
     5     {
     6         /// <summary>
     7         /// Gets the unique-identifier of the repository context.
     8         /// </summary>
     9         Guid ID { get; }
    10         /// <summary>
    11         /// Registers a new object to the repository context.
    12         /// </summary>
    13         /// <typeparam name="TAggregateRoot">The type of the aggregate root.</typeparam>
    14         /// <param name="obj">The object to be registered.</param>
    15         void RegisterNew<TAggregateRoot>(TAggregateRoot obj)
    16             where TAggregateRoot : class, IAggregateRoot;
    17         /// <summary>
    18         /// Registers a modified object to the repository context.
    19         /// </summary>
    20         /// <typeparam name="TAggregateRoot">The type of the aggregate root.</typeparam>
    21         /// <param name="obj">The object to be registered.</param>
    22         void RegisterModified<TAggregateRoot>(TAggregateRoot obj)
    23             where TAggregateRoot : class, IAggregateRoot;
    24         /// <summary>
    25         /// Registers a deleted object to the repository context.
    26         /// </summary>
    27         /// <typeparam name="TAggregateRoot">The type of the aggregate root.</typeparam>
    28         /// <param name="obj">The object to be registered.</param>
    29         void RegisterDeleted<TAggregateRoot>(TAggregateRoot obj)
    30             where TAggregateRoot : class, IAggregateRoot;
    31     }

      UnitOfWork的具体操作会在EntityFrameworkRepositoryContext中完成,并在EntityFrameworkRepository中注册IEntityFrameworkRepositoryContext接口类型映射,EntityFrameworkRepository作用就是在Repository集合中去完成持久化,工作单元的持久化,看下EntityFrameworkRepositoryContext中的示例代码:

     1 using System.Data.Entity;
     2 using System.Threading;
     3 
     4 namespace ByteartRetail.Domain.Repositories.EntityFramework
     5 {
     6     public class EntityFrameworkRepositoryContext : RepositoryContext, IEntityFrameworkRepositoryContext
     7     {
     8         private readonly ThreadLocal<ByteartRetailDbContext> localCtx = new ThreadLocal<ByteartRetailDbContext>(() => new ByteartRetailDbContext());
     9 
    10         public override void RegisterDeleted<TAggregateRoot>(TAggregateRoot obj)
    11         {
    12             localCtx.Value.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Deleted;
    13             Committed = false;
    14         }
    15 
    16         public override void RegisterModified<TAggregateRoot>(TAggregateRoot obj)
    17         {
    18             localCtx.Value.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Modified;
    19             Committed = false;
    20         }
    21 
    22         public override void RegisterNew<TAggregateRoot>(TAggregateRoot obj)
    23         {
    24             localCtx.Value.Entry<TAggregateRoot>(obj).State = System.Data.EntityState.Added;
    25             Committed = false;
    26         }
    27 
    28         public override void Commit()
    29         {
    30             if (!Committed)
    31             {
    32                 localCtx.Value.SaveChanges();
    33                 Committed = true;
    34             }
    35         }
    36 
    37         public override void Rollback()
    38         {
    39             Committed = false;
    40         }
    41 
    42         protected override void Dispose(bool disposing)
    43         {
    44             if (disposing)
    45             {
    46                 if (!Committed)
    47                     Commit();
    48                 localCtx.Value.Dispose();
    49                 localCtx.Dispose();
    50                 base.Dispose(disposing);
    51             }
    52         }
    53 
    54         #region IEntityFrameworkRepositoryContext Members
    55 
    56         public DbContext Context
    57         {
    58             get { return localCtx.Value; }
    59         }
    60 
    61         #endregion
    62     }
    63 }

      UnitOfWork的操作会贯彻所有Repository的持久化,在Byteart Retail项目中的领域层,有很多的类和接口关联,比如IEntity、IAggregateRoot、IRepository、IRepositoryContext、Repository、RepositoryContext、EntityFrameworkRepositoryContext等等,用类图表示有时候不太直观,画了一个简单的示例图,方便理解UnitOfWork在DDD中的应用始末

    点击查看大图

      左半部分:IEntity、IAggreateRoot、IRepository<TAggregateRoot>、Repository<TAggregateRoot>等,可以看做是仓储库,和领域模型相关(存在于领域层),右半部:IUnitOfWork、IRepositoryContext、RepositoryContext、IEntityFrameworkRepositoryContext等,可以看做是仓储的持久化(工作单元),这两者通过EntityFrameworkRepository进行IoC注册对象,完成所有Repository的整个工作单元的协调、管理。

    后记

      You don't know you're beautiful,that's what makes you beautiful ! -你不知道你是如此的美丽动人,这就是你美丽动人的所在!

      如果你觉得本篇文章对你有所帮助,请点击右下部“推荐”,^_^

      参考资料:

  • 相关阅读:
    HDU 1269 迷宫城堡
    HDU 4771 Stealing Harry Potter's Precious
    HDU 4772 Zhuge Liang's Password
    HDU 1690 Bus System
    HDU 2112 HDU Today
    HDU 1385 Minimum Transport Cost
    HDU 1596 find the safest road
    HDU 2680 Choose the best route
    HDU 2066 一个人的旅行
    AssetBundle管理机制(下)
  • 原文地址:https://www.cnblogs.com/xishuai/p/3750154.html
Copyright © 2011-2022 走看看