.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个特性,也算是其功能: 使用同一上下文 跟踪实体的状态 保障事务一致性 工作单元模式 主要关注事务,所以重点在事务上. 在共享层的基础建设类库中 ...
随机推荐
- activity结束之后刷新之前的activity的内容
点击添加按钮之后-----弹出一个新的activity--------在新的activity将数据输入保存之后,关闭当前的activity回到之前的activity刷新内容 实现:使用onActivi ...
- JS实现返回对象的详细信息
使用JS有时会需要打印出对象的详细信息,下面方法可以实现: function ShowObjProperty(Obj) { var PropertyList=''; var PropertyCount ...
- 实现iOS图片等资源文件的热更新化(三):动态的资源文件夹
简介 此文,将尝试动态从某个不确定的文件夹中加载资源文件.文章,会继续完善自定义的 imageNamed 函数,并为下一篇文章铺垫. 这么做的意义 正如我们经常所说的那样,大多数情景知道做事的意义往往 ...
- .net程序部署(mono方式)
某一次 我同事用了这个词 ,说这样才显得够专业 擦.把某某项目 部署到服务器上 .擦 不就是拷个文件过去运行么.月亮 还是绵羊 我搞不清楚了 咱英文不好,绵羊叫的声音?.你就叫我山寨程序猿 随意 一 ...
- C#学习记录
转眼几个月没更博了,把几个月前学C#的笔记发一下,就记录了点教重要的点子而已 1.打印 Console.WriteLine(); 打印 Console.ReadKey(); 按一个按键继续执行 Con ...
- HTML5火焰文字特效DEMO演示
效果展示:http://hovertree.com/texiao/html5/26/ 效果图: 扫描二维码查看效果:
- ASP.NET 5 已死 - 隆重介绍 ASP.NET Core 1.0 和 .NET Core 1.0
还没正式登场就死了?不能怪我标题党,是大神Scott在他博客上这么说的,我只是翻译了一下. 在1月20号最新的ASP.NET Community Standup视频中,微软aspnet开发组的大帅哥 ...
- ERROR LazyInitializationException:19 - failed to lazily initialize a collection of role: com.goodfan.entity.BeanA.beanB, no session or session was closed
1. 问题, 当使用JSONArray.fromObject(List<BeanA>)时, beanA中含有BeanB的属性beanB时,会报这个错 2. 解决办法: 使用jsonconf ...
- SQL注入—我是如何一步步攻破一家互联网公司的
最近在研究Web安全相关的知识,特别是SQL注入类的相关知识.接触了一些与SQL注入相关的工具.周末在家闲着无聊,想把平时学的东东结合起来攻击一下身边某个小伙伴去的公司,看看能不能得逞.不试不知道,一 ...
- 玩转 H5 下拉上滑动效果
在APP中我们经常会在页面下拉时看到一些动效,例如下拉图片跟随放大.下拉刷新出现loading动画等,这个交互细节在各个主流APP以及手机原生系统中随处可见,能为APP增添个性亮点. 一.背景 在我们 ...