.NET应用架构设计—工作单元模式(摆脱过程式代码的重要思想,逆袭DDD)

简介:

阅读目录:

  • 1.背景介绍

  • 2.过程式代码的真正困境

  • 3.工作单元模式的简单示例

  • 4.总结

1.背景介绍

一直都在谈论面向对象开发,但是开发企业应用系统时,使用面向对象开发最大的问题就是在于,多个对象之间的互操作需要涉及数据库操作。两个业务逻辑对象彼此之间需要互相调用,如果之间的互相操作是在一个业务事务范围内的,很容易完成,但是如果本次业务逻辑操作涉及到多个业务对象一起协作完成时问题就来了。

在以往,我们使用过程式的代码(事务脚本模式),将所有与本次业务事务范围内相关的所有逻辑都写在一个大的代码中,就算你适当的提取重复代码,效果也不大,因为你永远都摆脱不了夸多个对象互相操作的困境。如何确认你是否在这个困境中,你只要看你的所有事务操作的入口都只有一个业务方法。比如当你添加一个订单的时候,你同时将订单跟随的商品都一起在“添加订单”的方法中处理的,而不是在另外一个“添加订单商品”的方法中,这两个方法位于不同的表模块类中。

本章将介绍一个模式,此模式专门用来在开发企业应用系统时,协调多个业务对象在一个业务事务范围内,保证一个完整的事务。

2.过程式代码的困境

其实开发应用系统与开发某个框架或者组件之间的最大区别就是需要考虑数据的持久化,而持久化的逻辑也是和业务逻辑息息相关的,某个方法的最后动作就有可能是添加一行数据或者更新一个字段。而非应用系统的代码往往在最后的时候才去统一刷新最终的持久化文件,而且此类程序很少存在事务性数据操作。就算有,使用内存事务处理也是比较简单的,不需要考虑那么多的服务端的事情。

我之前也写过很多组件、框架,虽然谈不上什么复杂的东西,但是给我的经验和感悟就是,如何将其细致的设计粒度用在企业应用系统中,如何进行复杂而细致的OO设计开发。其实,如果我们不能够打破过程式代码的格局,那么看再多的OO知识也是心有余而力不足,反而会让你产生很多负面的情绪(因为我有过这个经历)。

其实我们还是缺少正确的方法而已,本文中UnitOfWork模式将帮助我们走出过程式的业务逻辑,走向起码的面向对象开发。有了UnitOfWork你可以随意使用Table module 、Activa Record、Domin Driven 模式,而且你可以根据自己的项目需要将其在大的布局上进行SOA划分(CQRS),让各个模式在各自适合的场景中发挥极致。

3.工作单元模式的简单示例

这里我们依然使用简单的订单购物业务作为示例来讲,毕竟大家都懂得这部分的的业务概念。本实例业务层使用Active Record模式。

1
2
3
4
5
6
7
8
9
10
11
namespace  OrderManager.Business
{
     using  System.Collections.Generic;
 
     public  partial  class  Order
     {
         public  long  OId {  get set ; }
 
         public  List<OrderProducts> Products {  get set ; }
     }
}

Order活动记录对象的字段部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
namespace  OrderManager.Business
{
     public  partial  class  Order
     {
         public  bool  CheckOrder()
         {
             //执行部分业务验证工作
             if  ( this .OId <= 0)  return  false ;
 
             return  true ;
         }
     }
}

Order活动记录对象主体,纯粹为了演示而用,包含了一个简单的判断业务逻辑。

1
2
3
4
5
6
7
8
9
10
11
namespace  OrderManager.Business
{
     public  partial  class  OrderProducts
     {
         public  long  OrderId {  get set ; }
 
         public  long  PId {  get set ; }
 
         public  float  Price {  get set ; }
     }
}

订单商品部分字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
namespace  OrderManager.Business
{
     public  partial  class  OrderProducts
     {
         public  bool  CheckProducts()
         {
             //执行部分业务验证工作
             if  ( this .OrderId <= 0)  return  false ;
 
             return  true ;
         }
     }
}

每一个商品都包含了自己的逻辑验证。

我们接着看一下应用层入口方法是如何协调两个活动记录对象之间的业务操作和数据存储的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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工具来动态注入。

我们接着看一下数据层代码,数据层我使用表入口模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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();
         }
     }
}

这是一个表入口基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 ;
         }
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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语句来插入数据库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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化架构,很少再有多大的项目在一个解决方案里面。

最后还是那句话,提供一个参考资料,如果有兴趣可以进一步交流具体的设计,由于时间关系文章就到这里了,谢谢大家。





 本文转自 王清培 51CTO博客,原文链接:http://blog.51cto.com/wangqingpei557/1547592,如需转载请自行联系原作者

相关文章
|
18天前
|
机器学习/深度学习 文字识别 监控
安全监控系统:技术架构与应用解析
该系统采用模块化设计,集成了行为识别、视频监控、人脸识别、危险区域检测、异常事件检测、日志追溯及消息推送等功能,并可选配OCR识别模块。基于深度学习与开源技术栈(如TensorFlow、OpenCV),系统具备高精度、低延迟特点,支持实时分析儿童行为、监测危险区域、识别异常事件,并将结果推送给教师或家长。同时兼容主流硬件,支持本地化推理与分布式处理,确保可靠性与扩展性,为幼儿园安全管理提供全面解决方案。
|
4月前
|
运维 Cloud Native 持续交付
深入理解云原生架构及其在现代企业中的应用
随着数字化转型的浪潮席卷全球,企业正面临着前所未有的挑战与机遇。云计算技术的迅猛发展,特别是云原生架构的兴起,正在重塑企业的IT基础设施和软件开发模式。本文将深入探讨云原生的核心概念、关键技术以及如何在企业中实施云原生策略,以实现更高效的资源利用和更快的市场响应速度。通过分析云原生架构的优势和面临的挑战,我们将揭示它如何助力企业在激烈的市场竞争中保持领先地位。
113 13
|
8天前
|
人工智能 JavaScript 开发工具
MCP详解:背景、架构与应用
模型上下文协议(MCP)是由Anthropic提出的开源标准,旨在解决大语言模型与外部数据源和工具集成的难题。作为AI领域的“USB-C接口”,MCP通过标准化、双向通信通道连接模型与外部服务,支持资源访问、工具调用及提示模板交互。其架构基于客户端-服务器模型,提供Python、TypeScript等多语言SDK,方便开发者快速构建服务。MCP已广泛应用于文件系统、数据库、网页浏览等领域,并被阿里云百炼平台引入,助力快速搭建智能助手。未来,MCP有望成为连接大模型与现实世界的通用标准,推动AI生态繁荣发展。
135 8
|
27天前
|
人工智能 前端开发 Java
DDD四层架构和MVC三层架构的个人理解和学习笔记
领域驱动设计(DDD)是一种以业务为核心的设计方法,与传统MVC架构不同,DDD将业务逻辑拆分为应用层和领域层,更关注业务领域而非数据库设计。其四层架构包括:Interface(接口层)、Application(应用层)、Domain(领域层)和Infrastructure(基础层)。各层职责分明,避免跨层调用,确保业务逻辑清晰。代码实现中,通过DTO、Entity、DO等对象的转换,结合ProtoBuf协议,完成请求与响应的处理流程。为提高复用性,实际项目中可增加Common层存放公共依赖。DDD强调从业务出发设计软件,适应复杂业务场景,是微服务架构的重要设计思想。
|
1月前
|
消息中间件 人工智能 自然语言处理
基于 RocketMQ 事件驱动架构的 AI 应用实践
基于 RocketMQ 事件驱动架构的 AI 应用实践
|
1月前
|
存储 缓存 API
类似ComfyUI和Midjourney这样的文生图图生图应用的API与服务架构该怎么设计
文生图图生图应用的API与服务架构分析。或和微服务类似,但是不同。ComfyUI其 API 架构设计为我们理解此类应用提供了很好的参考模型。但距离生产级别的应用差距还有很远。
113 0
|
3月前
|
C# Android开发 iOS开发
2025年全面的.NET跨平台应用框架推荐
2025年全面的.NET跨平台应用框架推荐
154 23
|
3月前
|
容灾 网络协议 数据库
云卓越架构:云上网络稳定性建设和应用稳定性治理最佳实践
本文介绍了云上网络稳定性体系建设的关键内容,包括面向失败的架构设计、可观测性与应急恢复、客户案例及阿里巴巴的核心电商架构演进。首先强调了网络稳定性的挑战及其应对策略,如责任共担模型和冗余设计。接着详细探讨了多可用区部署、弹性架构规划及跨地域容灾设计的最佳实践,特别是阿里云的产品和技术如何助力实现高可用性和快速故障恢复。最后通过具体案例展示了秒级故障转移的效果,以及同城多活架构下的实际应用。这些措施共同确保了业务在面对网络故障时的持续稳定运行。
|
4月前
|
存储 NoSQL MongoDB
.NET MongoDB数据仓储和工作单元模式封装
.NET MongoDB数据仓储和工作单元模式封装
71 15
|
4月前
|
算法 Java 测试技术
使用 BenchmarkDotNet 对 .NET 代码进行性能基准测试
使用 BenchmarkDotNet 对 .NET 代码进行性能基准测试
111 13