zoukankan      html  css  js  c++  java
  • 企业模式之Unit Of Work模式

      在开始UnitOfWork模式之前有必要回顾下我们耳熟能详的Data Access Object(DAO)模式,即数据访问对象。DAO是一种简单的模式,我们构建应用的时候经常会使用到它,它的功能就是将DAL元素从应用程序中分离出来,在经典的三层架构中,我们会将数据持久化工作单独分离出来,封装成DAL层。但是,DAO并没有隐藏它面对是一张张数据表,而且通常情况我们会为数据库中的每一张表创建一个DAO类,想必大家对这种方式的极度的不爽了,。

         由于DAO模式与数据表是一对一匹配的关系,因此DAO模式很好的配合了Active Record和Transaction Script业务模式,尤其是Table Module。正因为这种与数据表一对一匹配关系,使我对DAO模式深恶痛绝。

      Unit Of Work模式,即工作单元,它是一种数据访问模式。它是用来维护一个由已经被业务修改(如增加、删除和更新等)的业务对象组成的列表。它负责协调这些业务对象的持久化工作及并发问题。那它是怎么来维护的一系列业务对象组成的列表持久化工作的呢?通过事务。Unit Of Work模式会记录所有对象模型修改过的信息,在提交的时候,一次性修改,并把结果同步到数据库。 这个过程通常被封装在事务中。所以在DAL中采用Unit Of Work模式好处就在于能够确保数据的完整性,如果在持有一系列业务对象(同属于一个事务)的过程中出现问题,就可以将所有的修改回滚,以确保数据始终处于有效状态,不会出现脏数据。

      在这里我们,使用一个简单的银行领域对两个帐号之间的转账进行举例

         首先如图进行分层搭建基础框架

         

      总共分为四层依次是:    ---> 引用关系

      UnitOfWork.Console        --->UnitOfWork.Infrastructure、UnitOfWork.Model、UnitOfWork.Repository

      UnitOfWork.Infrastructure

      UnitOfWork.Model    --->UnitOfWork.Infrastructure

      UnitOfWork.Repository  --->UnitOfWork.Model、UnitOfWork.Infrastructure

      这不是经典的领域驱动架构,因为业务简单就进行简单搭建。

      UnitOfWork.Infrastructure:

      首先,在UnitOfWork.Infrastructure建了一个Domain文件夹,里面只建了一个IAggregateRoot接口,Unit Of Work操作的实体必须是实现IAggregateRoot接口的。

        /// <summary>
        /// 标识接口,定义聚合根
        /// </summary>
        public class IAggregateRoot
        {
    
        }

      建立UnitOfWork文件夹,在里面添加一个IUnitOfWorkRepository接口

        public interface IUnitOfWorkRepository
        {
            //新增
            void PersistCreationOf(IAggregateRoot entity);
            //更新
            void PersistUpdateOf(IAggregateRoot entity);
            //删除
            void PersistDeletionOf(IAggregateRoot entity);
        }

      我们再向UnitOfWork文件夹中添加一个IUnitOfWork接口,IUnitOfWork接口在注册更新、新增和删除时,需要IUnitOfWorkRepository,这样再提交Commit,UnitOfWork可以将真正持久化的工作委托给适合的具体实现对象,其实就是将持久化工作交给了IUnitOfWorkRepository的实现类,我们稍后看看IUnitOfWork的实现类你就清楚了。

      public interface IUnitOfWork
        {
            /// <summary>
            /// 更新
            /// </summary>
            /// <param name="entity"></param>
            /// <param name="unitofWorkRepository"></param>
            void RegisterUpdate(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
            /// <summary>
            /// 新增
            /// </summary>
            /// <param name="entity"></param>
            /// <param name="unitofWorkRepository"></param>
            void RegisterAdd(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
            /// <summary>
            /// 删除
            /// </summary>
            /// <param name="entity"></param>
            /// <param name="unitofWorkRepository"></param>
            void RegisterRemoved(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository);
            /// <summary>
            /// 提交
            /// </summary>
            void Commit();
        }

      顺便说一句,在UnitOfWork.Infrastructure,我还建立的Common文件夹,Logging文件夹,所要表达的意思是Infrastructure意为基础设施层,我们可以将通用的组件放到这里面,比如日志组件,邮件组件等。

          好了,回顾下,我们在UnitOfWork.Infrastructure中其实什么业务都没有处理,只定义了三个接口。

      UnitOfWork.Model

      接下来,说说这层干了什么事吧!这一层主要是处理两个账户之间转账的业务。

      向UnitOfWork.Model中添加一个Account类,实现IAggregateRoot接口,表示它是一个聚合根,可以被Unit Of Work操作。

        /// <summary>
        /// 账户类,表示Account是集合根
        /// </summary>
        public class Account : IAggregateRoot
        {
            public Account(decimal balance)
            {
                Balance = balance;
            }
            /// <summary>
            /// 账户余额
            /// </summary>
            public decimal Balance { get; set; }
        }

      为了持久化Account类,我们添加的一个仅包含了示例有关的的Repository接口,即IAccountRepository,只是简单的示例。

        /// <summary>
        /// 定义持久化操作
        /// </summary>
        public interface IAccountRepository
        {
            /// <summary>
            /// 更新
            /// </summary>
            /// <param name="account"></param>
            void Save(Account account);
            /// <summary>
            /// 新增
            /// </summary>
            /// <param name="account"></param>
            void Add(Account account);
            /// <summary>
            /// 删除
            /// </summary>
            /// <param name="account"></param>
            void Remove(Account account);
        }

      为了完成转账的业务,我们需要创建一个服务类来协调两个账户之间的转账工作,如AccountService类,在AccountService类中,通过构造函数初始化了IAccountRepository和IUnitOfWork。在完成转账后,它们都调用了账户Repository进行持久化。最后,通过Unit Of Work的Commit来确保该笔交易的完成。

        public class AccountService
        {
            private IAccountRepository _accountRepository;
            private IUnitOfWork _unitOfWork;
    
            public AccountService(IAccountRepository accountRepository,
                                  IUnitOfWork unitOfWork)
            {
                _accountRepository = accountRepository;
                _unitOfWork = unitOfWork;
            }
    
            /// <summary>
            /// 转账
            /// </summary>
            /// <param name="from"></param>
            /// <param name="to"></param>
            /// <param name="amount"></param>
            public void Transfer(Account from, Account to, decimal amount)
            {
                if (from.Balance >= amount)
                {
                    from.Balance -= amount;
                    to.Balance += amount;
    
                    _accountRepository.Save(from);
                    _accountRepository.Save(to);
                    _unitOfWork.Commit();
                }
            }
        }

      总结下,在UnitOfWork.Model中我们定义的一个Account类,定义了一个持久化Account类的接口,以及转账业务的完成。下面我们要进入UnitOfWork.Repository探究Repository和Unit Of Work之间是怎么交互的?

      UnitOfWork.Repository:

      在UnitOfWork.Repository,添加了一个NHUnitOfWork类,实现了UnitOfWork.Infrastructure.UnitOfWork中的IUnitOfWork接口,为什么定义到这里。因为在项目开发中你可能有NHbernator的Repository和EF的Repository。还记得我在讲解IUnitOfWork接口时,曾说过这样一句话“IUnitOfWork将持久化工作交给了IUnitOfWorkRepository的实现类”,在这里你就会找到答案了。

        public class NHUnitOfWork : IUnitOfWork
        {
            private Dictionary<IAggregateRoot, IUnitOfWorkRepository> addedEntities;
            private Dictionary<IAggregateRoot, IUnitOfWorkRepository> changedEntities;
            private Dictionary<IAggregateRoot, IUnitOfWorkRepository> deletedEntities;
    
            public NHUnitOfWork()
            {
                addedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
                changedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
                deletedEntities = new Dictionary<IAggregateRoot, IUnitOfWorkRepository>();
            }
    
            public void RegisterUpdate(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)
            {
                if (!changedEntities.ContainsKey(entity))
                {
                    changedEntities.Add(entity, unitofWorkRepository);
                }
            }
    
            public void RegisterAdd(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)
            {
                if (!addedEntities.ContainsKey(entity))
                {
                    addedEntities.Add(entity, unitofWorkRepository);
                };
            }
    
            public void RegisterRemoved(IAggregateRoot entity, IUnitOfWorkRepository unitofWorkRepository)
            {
                if (!deletedEntities.ContainsKey(entity))
                {
                    deletedEntities.Add(entity, unitofWorkRepository);
                }
            }
    
            public void Commit()
            {
                using (TransactionScope scope = new TransactionScope())
                {
                    foreach (IAggregateRoot entity in this.addedEntities.Keys)
                    {
                        this.addedEntities[entity].PersistCreationOf(entity);
                    }
    
                    foreach (IAggregateRoot entity in this.changedEntities.Keys)
                    {
                        this.changedEntities[entity].PersistUpdateOf(entity);
                    }
    
                    foreach (IAggregateRoot entity in this.deletedEntities.Keys)
                    {
                        this.deletedEntities[entity].PersistDeletionOf(entity);
                    }
    
                    scope.Complete();
                }
            }

      接下来,再添加一个AccountRepository类,这个类实现了两个接口,IAccountRepository和IUnitOfWorkRepository接口。IAccountRepository中的方法就是简单得将工作交给了Unit Of Work,传入待持久化的实体及Repository(实现了IUnitOfWorkRepository)引用。最后Unit Of Work 引用Repository的IUnitOfWorkRepository契约来完成真正的持久化工作。

        public class AccountRepository : IAccountRepository,IUnitOfWorkRepository
        {
            private IUnitOfWork _unitOfWork;
    
            public AccountRepository(IUnitOfWork unitOfWork)
            {
                _unitOfWork = unitOfWork;
            }
    
            public void Save(Account account)
            {
                _unitOfWork.RegisterUpdate(account, this);
            }
    
            public void Add(Account account)
            {
                _unitOfWork.RegisterAdd(account, this);
            }
    
            public void Remove(Account account)
            {
                _unitOfWork.RegisterRemoved(account, this);
            }
    
            public void PersistUpdateOf(IAggregateRoot entity)
            {
                // ADO.net code to update the entity...真正的SQL实现
            }
    
            public void PersistCreationOf(IAggregateRoot entity)
            {
                // ADO.net code to Add the entity...真正的SQL实现
            }
    
            public void PersistDeletionOf(IAggregateRoot entity)
            {
                // ADO.net code to delete the entity...真正的SQL实现
            }
        }    

      总结下,UnitOfWork.Repository这里才是真正纠结的地方。首先,Unit Of Work加载实体对象(Accont)和实体对应的Repository对象(AccountRepository);然后通过Unit Of Work的Commit方法,循环转调Repository对象(AccountRepository)的持久化方法,进行实体对象(Accont)的持久化工作。多调试就明白了。

      UnitOfWork.Console:

      接下来,就是最后的控制台程序了。  

        class Program
        {
            static void Main(string[] args)
            {
                Account a = new Account(1000);
                System.Console.WriteLine("现在张三,存有{0}", a.Balance);
                Account b = new Account(200);
                System.Console.WriteLine("现在李四,存有{0}", b.Balance);
                System.Console.WriteLine("张三准备转500元给李四,转战开始了......");
    
                //声明要使用的UnitOfWork
                IUnitOfWork nhUnitOfWork = new NHUnitOfWork();
    
                //声明要使用的Repository
                IAccountRepository accountRepository = new AccountRepository(nhUnitOfWork);
    
                AccountService service = new AccountService(accountRepository, nhUnitOfWork);
    
                service.Transfer(a,b,500);
                System.Console.WriteLine("转账结束");
                System.Console.WriteLine("张三当前余额:{0}",a.Balance);
                System.Console.WriteLine("李四当前余额:{0}",b.Balance);
    
                System.Console.ReadKey();
            }
        }

      好了,睡觉了!

  • 相关阅读:
    编写安全检测脚本
    编写监控脚本
    编写一键部署软件脚本
    awk扩展应用
    sed基本用法
    字符串截取及切割,正则表达式,expect预期交互
    For,while,case,shell循环结构
    mybatis使用associaton进行分步查询
    mybatis中封装结果集常见示例
    Mybatis获取数据库自增主键
  • 原文地址:https://www.cnblogs.com/zxj159/p/3505457.html
Copyright © 2011-2022 走看看