.NET应用架构设计—工作单元模式(摆脱过程式代码的重要思想,代替DDD实现轻量级业务)
阅读目录:
- 1.背景介绍
- 2.过程式代码的真正困境
- 3.工作单元模式的简单示例
- 4.总结
1.背景介绍
一直都在谈论面向对象开发,但是开发企业应用系统时,使用面向对象开发最大的问题就是在于,多个对象之间的互操作需要涉及数据库操作。两个业务逻辑对象彼此之间需要互相调用,如果之间的互相操作是在一个业务事务范围内的,很容易完成,但是如果本次业务逻辑操作涉及到多个业务对象一起协作完成时问题就来了。
在以往,我们使用过程式的代码(事务脚本模式),将所有与本次业务事务范围内相关的所有逻辑都写在一个大的代码中,就算你适当的提取重复代码,效果也不大,因为你永远都摆脱不了夸多个对象互相操作的困境。如何确认你是否在这个困境中,你只要看你的所有事务操作的入口都只有一个业务方法。比如当你添加一个订单的时候,你同时将订单跟随的商品都一起在“添加订单”的方法中处理的,而不是在另外一个“添加订单商品”的方法中,这两个方法位于不同的表模块类中。
本章将介绍一个模式,此模式专门用来在开发企业应用系统时,协调多个业务对象在一个业务事务范围内,保证一个完整的事务。
2.过程式代码的困境
其实开发应用系统与开发某个框架或者组件之间的最大区别就是需要考虑数据的持久化,而持久化的逻辑也是和业务逻辑息息相关的,某个方法的最后动作就有可能是添加一行数据或者更新一个字段。而非应用系统的代码往往在最后的时候才去统一刷新最终的持久化文件,而且此类程序很少存在事务性数据操作。就算有,使用内存事务处理也是比较简单的,不需要考虑那么多的服务端的事情。
我之前也写过很多组件、框架,虽然谈不上什么复杂的东西,但是给我的经验和感悟就是,如何将其细致的设计粒度用在企业应用系统中,如何进行复杂而细致的OO设计开发。其实,如果我们不能够打破过程式代码的格局,那么看再多的OO知识也是心有余而力不足,反而会让你产生很多负面的情绪(因为我有过这个经历)。
其实我们还是缺少正确的方法而已,本文中UnitOfWork模式将帮助我们走出过程式的业务逻辑,走向起码的面向对象开发。有了UnitOfWork你可以随意使用Table module 、Activa Record、Domin Driven 模式,而且你可以根据自己的项目需要将其在大的布局上进行SOA划分(CQRS),让各个模式在各自适合的场景中发挥极致。
3.工作单元模式的简单示例
这里我们依然使用简单的订单购物业务作为示例来讲,毕竟大家都懂得这部分的的业务概念。本实例业务层使用Active Record模式。
namespace OrderManager.Business
{
using System.Collections.Generic; public partial class Order
{
public long OId { get; set; } public List<OrderProducts> Products { get; set; }
}
}
Order活动记录对象的字段部分。
namespace OrderManager.Business
{
public partial class Order
{
public bool CheckOrder()
{
//执行部分业务验证工作
if (this.OId <= ) return false; return true;
}
}
}
Order活动记录对象主体,纯粹为了演示而用,包含了一个简单的判断业务逻辑。
namespace OrderManager.Business
{
public partial class OrderProducts
{
public long OrderId { get; set; } public long PId { get; set; } public float Price { get; set; }
}
}
订单商品部分字段。
namespace OrderManager.Business
{
public partial class OrderProducts
{
public bool CheckProducts()
{
//执行部分业务验证工作
if (this.OrderId <= ) return false; return true;
}
}
}
每一个商品都包含了自己的逻辑验证。
我们接着看一下应用层入口方法是如何协调两个活动记录对象之间的业务操作和数据存储的。
namespace OrderManager
{
using OrderManager.Business;
using OrderManager.DataSource; public class OrderManagerController : ControllerBase
{
public bool AddOrder(Order order)
{
using (UnitOfWork unitOfWork = new UnitOfWork())
{
order.CheckOrder();//执行业务检查 order.Products.ForEach(item =>
{
item.CheckProducts();//执行每个活动记录对象的业务检查,这里也可以使用表模块来处理。
}); OrderGateway orderGateway = new OrderGateway(unitOfWork);
var orderDbResult = orderGateway.AddOrder(order);//第一个数据库表操作 OrderProductsGateway productGateway = new OrderProductsGateway(unitOfWork);
var productDbResult = productGateway.AddOrderProducts(order.Products);//第二个数据库表操作 if (orderDbResult && productDbResult)
{
if (unitOfWork.Commit())
{
this.SendOrderIntegrationMssage(order);//发送成功集成订单消息 return true;
} this.PushOrderProcessQueue(order);//将本次订单发送到处理队列中
return false;
} this.LogBusinessException(order);//记录一个业务处理异常LOG,以备排查问题。
return false;
}
}
}
}
为了简单演示示例,我直接使用实例化的方式来构造数据访问对象,实际使用时可以使用IOC工具来动态注入。
我们接着看一下数据层代码,数据层我使用表入口模式。
namespace OrderManager.DataSource
{
public abstract class GatewayBase
{
protected UnitOfWork UnitOfWork { get; private set; } public GatewayBase(UnitOfWork unit)
{
this.UnitOfWork = unit;
} public bool Commit()
{
return this.UnitOfWork.Commit();
} public void Rollback()
{
this.UnitOfWork.Rollback();
}
}
}
这是一个表入口基类。
namespace OrderManager.DataSource
{
using OrderManager.Business; public class OrderGateway : GatewayBase
{
public OrderGateway(UnitOfWork unit) : base(unit) { } public bool AddOrder(Order order)
{
//这里可以使用你所熟悉的拼接SQL的方式直接操作数据库,而不需要ORM。
return true;
}
}
}
namespace OrderManager.DataSource
{
using OrderManager.Business;
using System.Collections.Generic; public class OrderProductsGateway : GatewayBase
{
public OrderProductsGateway(UnitOfWork unit) : base(unit) { } public bool AddOrderProducts(List<OrderProducts> products)
{
//这里可以使用你所熟悉的拼接SQL的方式直接操作数据库,而不需要ORM。
return true;
}
}
}
这是两个表入口对象,其实这部分代码是大家都比较熟悉的,所以我这里省略了,你可以直接拼接SQL语句来插入数据库。
namespace OrderManager.DataSource
{
using System; public class UnitOfWork : IDisposable
{
public void Dispose()
{
throw new NotImplementedException();
} public bool Commit()
{
return true;
} public void Rollback()
{
//
}
}
}
UnitOfWrok对象其实就是对数据库对象的System.Data.Common.DbConnection对象的封装,这里你可以使用你熟悉的方式来构造这个数据库连接对象和开启事务。
其实值得我们去欣赏的是应用控制器中的代码,在这里很协调的处理各个逻辑,最后记录下一些必要的日志和发送一些集成消息。你是不是发现你完全可以不使用DDD也可以处理部分业务系统了。
4.总结
活动记录模式+表入口模式+工作单元模式,其实我觉得可以很好的处理中小型业务逻辑,随着现在SOA化架构,很少再有多大的项目在一个解决方案里面。
最后还是那句话,提供一个参考资料,如果有兴趣可以进一步交流具体的设计,由于时间关系文章就到这里了,谢谢大家。
.NET应用架构设计—工作单元模式(摆脱过程式代码的重要思想,代替DDD实现轻量级业务)的更多相关文章
- .NET应用架构设计—工作单位模式(摆脱程序代码的重要思想,反击DDD)
阅读文件夹: 1.背景介绍 2.过程式代码的真正困境 3.工作单元模式的简单演示样例 4.总结 1.背景介绍 一直都在谈论面向对象开发.可是开发企业应用系统时.使用面向对象开发最大的问题就是在于,多个 ...
- [.NET领域驱动设计实战系列]专题五:网上书店规约模式、工作单元模式的引入以及购物车的实现
一.前言 在前面2篇博文中,我分别介绍了规约模式和工作单元模式,有了前面2篇博文的铺垫之后,下面就具体看看如何把这两种模式引入到之前的网上书店案例里. 二.规约模式的引入 在第三专题我们已经详细介绍了 ...
- [.NET领域驱动设计实战系列]专题四:前期准备之工作单元模式(Unit Of Work)
一.前言 在前一专题中介绍了规约模式的实现,然后在仓储实现中,经常会涉及工作单元模式的实现.然而,在我的网上书店案例中也将引入工作单元模式,所以本专题将详细介绍下该模式,为后面案例的实现做一个铺垫. ...
- 仓储(Repository)和工作单元模式(UnitOfWork)
仓储和工作单元模式 仓储模式 为什么要用仓储模式 通常不建议在业务逻辑层直接访问数据库.因为这样可能会导致如下结果: 重复的代码 编程错误的可能性更高 业务数据的弱类型 更难集中处理数据,比如缓存 无 ...
- MVC+EF 理解和实现仓储模式和工作单元模式
MVC+EF 理解和实现仓储模式和工作单元模式 原文:Understanding Repository and Unit of Work Pattern and Implementing Generi ...
- Contoso 大学 - 9 - 实现仓储和工作单元模式
原文 Contoso 大学 - 9 - 实现仓储和工作单元模式 By Tom Dykstra, Tom Dykstra is a Senior Programming Writer on Micros ...
- 演练5-8:Contoso大学校园管理系统(实现存储池和工作单元模式)
在上一次的教程中,你已经使用继承来消除在 Student 和 Instructor 实体之间的重复代码.在这个教程中,你将要看到使用存储池和工作单元模式进行增.删.改.查的一些方法.像前面的教程一样, ...
- 关于工作单元模式——工作单元模式与EF结合的使用
工作单元模式往往和仓储模式一起使用,本篇文章讲到的是工作单元模式和仓储模式一起用来在ef外面包一层,其实EF本身就是工作单元模式和仓储模式使用的经典例子,其中DbContext就是工作单元,而每个Db ...
- 重新整理 .net core 实践篇—————工作单元模式[二十六]
前言 简单整理一下工作单元模式. 正文 工作单元模式有3个特性,也算是其功能: 使用同一上下文 跟踪实体的状态 保障事务一致性 工作单元模式 主要关注事务,所以重点在事务上. 在共享层的基础建设类库中 ...
随机推荐
- Macaca自动化测试之PC端测试
Macaca是一套完整的自动化测试解决方案.由阿里巴巴公司开源: http://macacajs.github.io/macaca/ 特点: 同时支持PC端和移动端(Android.iOS)自动化测试 ...
- Javascript数组常用方法
一.forEach对数组的遍历 二.map返回经过运算的新数组 三.filter返回满足条件的新数组 四.返回数组前后元素运算的结果 五.every遍历数组每项元素是否满足某个条件,全部满足返回tru ...
- 资源等待类型sys.dm_os_wait_stats
动态管理视图 sys.dm_os_wait_stats 返回执行的线程所遇到的所有等待的相关信息.可以使用该聚合视图来诊断 SQL Server 以及特定查询和批处理的性能问题. 列名 数据类型 说 ...
- Command and Query Responsibility Segregation (CQRS) Pattern 命令和查询职责分离(CQRS)模式
Segregate operations that read data from operations that update data by using separate interfaces. T ...
- 代码片段添加智能提示,打造一款人见人爱的ORM框架
SqlSugar ORM优点: 1.高性能,达到原生最高水准,比SqlHelper性能要高,比Dapper快30% 比EF快50% 2.支持多种数据库 ,sql版本更新最快,其它会定期更新,可以在多种 ...
- .Net语言 APP开发平台——Smobiler学习日志:如何在手机上开发仪表盘控件
最前面的话:Smobiler是一个在VS环境中使用.Net语言来开发APP的开发平台,也许比Xamarin更方便 一.目标样式 我们要实现上图中的效果,需要如下的操作: 1.从工具栏上的"S ...
- HTML5翻页电子书
体验效果:http://hovertree.com/texiao/jquery/60/ 图片请用正方形的 参考:http://hovertree.com/h/bjaf/d339euw9.htmhttp ...
- 谈I/O模型
一个IO操作涉及两个系统对象: 调用这个IO的用户Process/Thread 系统内核 - System Kernel 一个具体的Read操作包括两个阶段: 内核等待数据准备就绪:Waiting f ...
- 从零开始学Python06作业源码(仅供参考)
Python Version 2.7x 一,bin目录:程序启动入口 SelectLesson_start.py #!usr/bin/env python # -*- coding:utf-8 -*- ...
- JDK源码分析:hashCode()方法
提问: 1.hashCode()源码是怎么实现的. 2.hashCode()是为了配合基于散列的集合而设计的 3.hash数据结构,如何做到存取的时间复杂度为O(1)的.{函数算>逐个比较} 答 ...