.NET应用架构设计—工作单元模式(摆脱过程式代码的重要思想,代替DDD实现轻量级业务)

简介: 阅读目录: 1.背景介绍 2.过程式代码的真正困境 3.工作单元模式的简单示例 4.总结 1.背景介绍 一直都在谈论面向对象开发,但是开发企业应用系统时,使用面向对象开发最大的问题就是在于,多个对象之间的互操作需要涉及数据库操作。

阅读目录:

  • 1.背景介绍
  • 2.过程式代码的真正困境
  • 3.工作单元模式的简单示例
  • 4.总结

1.背景介绍

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

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

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

2.过程式代码的困境

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

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

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

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

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

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

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

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

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

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

订单商品部分字段。

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

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

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

 1 namespace OrderManager
 2 {
 3     using OrderManager.Business;
 4     using OrderManager.DataSource; 
 5 
 6     public class OrderManagerController : ControllerBase
 7     {
 8         public bool AddOrder(Order order)
 9         {
10             using (UnitOfWork unitOfWork = new UnitOfWork())
11             {
12                 order.CheckOrder();//执行业务检查 
13 
14                 order.Products.ForEach(item =>
15                 {
16                     item.CheckProducts();//执行每个活动记录对象的业务检查,这里也可以使用表模块来处理。
17                 }); 
18 
19                 OrderGateway orderGateway = new OrderGateway(unitOfWork);
20                 var orderDbResult = orderGateway.AddOrder(order);//第一个数据库表操作 
21 
22                 OrderProductsGateway productGateway = new OrderProductsGateway(unitOfWork);
23                 var productDbResult = productGateway.AddOrderProducts(order.Products);//第二个数据库表操作 
24 
25                 if (orderDbResult && productDbResult)
26                 {
27                     if (unitOfWork.Commit())
28                     {
29                         this.SendOrderIntegrationMssage(order);//发送成功集成订单消息 
30 
31                         return true;
32                     } 
33 
34                     this.PushOrderProcessQueue(order);//将本次订单发送到处理队列中
35                     return false;
36                 } 
37 
38                 this.LogBusinessException(order);//记录一个业务处理异常LOG,以备排查问题。
39                 return false;
40             }
41         }
42     }
43 }

为了简单演示示例,我直接使用实例化的方式来构造数据访问对象,实际使用时可以使用IOC工具来动态注入。

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

 1 namespace OrderManager.DataSource
 2 {
 3     public abstract class GatewayBase
 4     {
 5         protected UnitOfWork UnitOfWork { get; private set; } 
 6 
 7         public GatewayBase(UnitOfWork unit)
 8         {
 9             this.UnitOfWork = unit;
10         } 
11 
12         public bool Commit()
13         {
14             return this.UnitOfWork.Commit();
15         } 
16 
17         public void Rollback()
18         {
19             this.UnitOfWork.Rollback();
20         }
21     }
22 }

这是一个表入口基类。

 1 namespace OrderManager.DataSource
 2 {
 3     using OrderManager.Business; 
 4 
 5     public class OrderGateway : GatewayBase
 6     {
 7         public OrderGateway(UnitOfWork unit) : base(unit) { } 
 8 
 9         public bool AddOrder(Order order)
10         {
11             //这里可以使用你所熟悉的拼接SQL的方式直接操作数据库,而不需要ORM。
12             return true;
13         }
14     }
15 }
 1 namespace OrderManager.DataSource
 2 {
 3     using OrderManager.Business;
 4     using System.Collections.Generic; 
 5 
 6     public class OrderProductsGateway : GatewayBase
 7     {
 8         public OrderProductsGateway(UnitOfWork unit) : base(unit) { } 
 9 
10         public bool AddOrderProducts(List<OrderProducts> products)
11         {
12             //这里可以使用你所熟悉的拼接SQL的方式直接操作数据库,而不需要ORM。
13             return true;
14         }
15     }
16 }

这是两个表入口对象,其实这部分代码是大家都比较熟悉的,所以我这里省略了,你可以直接拼接SQL语句来插入数据库。

 1 namespace OrderManager.DataSource
 2 {
 3     using System; 
 4 
 5     public class UnitOfWork : IDisposable
 6     {
 7         public void Dispose()
 8         {
 9             throw new NotImplementedException();
10         } 
11 
12         public bool Commit()
13         {
14             return true;
15         } 
16 
17         public void Rollback()
18         {
19             //
20         }
21     }
22 }

 

UnitOfWrok对象其实就是对数据库对象的System.Data.Common.DbConnection对象的封装,这里你可以使用你熟悉的方式来构造这个数据库连接对象和开启事务。

其实值得我们去欣赏的是应用控制器中的代码,在这里很协调的处理各个逻辑,最后记录下一些必要的日志和发送一些集成消息。你是不是发现你完全可以不使用DDD也可以处理部分业务系统了。

4.总结

活动记录模式+表入口模式+工作单元模式,其实我觉得可以很好的处理中小型业务逻辑,随着现在SOA化架构,很少再有多大的项目在一个解决方案里面。

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

 

作者:王清培

出处:http://www.cnblogs.com/wangiqngpei557/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面

目录
相关文章
|
2天前
|
设计模式 人工智能 算法
编程之旅:从代码到架构的感悟
【9月更文挑战第33天】在编程的世界里,代码不仅是实现功能的工具,更是连接思想与现实的桥梁。本文将通过个人的编程经历,分享从编写第一行代码到设计系统架构的旅程,探索编程背后的哲学和技术演变。我们将一起思考,如何在代码的海洋中找到自己的航向,以及在这个过程中如何不断成长和适应变化。
|
13天前
|
JSON 监控 安全
探索微服务架构中的API网关模式
【9月更文挑战第22天】在微服务架构的海洋中,API网关如同一位智慧的守门人,不仅管理着服务的进出,还维护着整个系统的秩序。本文将带你一探究竟,看看这位守门人是如何工作的,以及它为何成为现代云原生应用不可或缺的一部分。从流量控制到安全防护,再到服务聚合,我们将一起解锁API网关的秘密。
|
23天前
|
机器学习/深度学习 测试技术 数据处理
KAN专家混合模型在高性能时间序列预测中的应用:RMoK模型架构探析与Python代码实验
Kolmogorov-Arnold网络(KAN)作为一种多层感知器(MLP)的替代方案,为深度学习领域带来新可能。尽管初期测试显示KAN在时间序列预测中的表现不佳,近期提出的可逆KAN混合模型(RMoK)显著提升了其性能。RMoK结合了Wav-KAN、JacobiKAN和TaylorKAN等多种专家层,通过门控网络动态选择最适合的专家层,从而灵活应对各种时间序列模式。实验结果显示,RMoK在多个数据集上表现出色,尤其是在长期预测任务中。未来研究将进一步探索RMoK在不同领域的应用潜力及其与其他先进技术的结合。
64 4
|
11天前
|
编解码 Linux 开发工具
Linux平台x86_64|aarch64架构RTMP推送|轻量级RTSP服务模块集成说明
支持x64_64架构、aarch64架构(需要glibc-2.21及以上版本的Linux系统, 需要libX11.so.6, 需要GLib–2.0, 需安装 libstdc++.so.6.0.21、GLIBCXX_3.4.21、 CXXABI_1.3.9)。
|
2月前
|
C# 微服务 Windows
模块化革命:揭秘WPF与微服务架构的完美融合——从单一职责原则到事件聚合器模式,构建高度解耦与可扩展的应用程序
【8月更文挑战第31天】本文探讨了如何在Windows Presentation Foundation(WPF)应用中借鉴微服务架构思想,实现模块化设计。通过将WPF应用分解为独立的功能模块,并利用事件聚合器实现模块间解耦通信,可以有效提升开发效率和系统可维护性。文中还提供了具体示例代码,展示了如何使用事件聚合器进行模块间通信,以及如何利用依赖注入进一步提高模块解耦程度。此方法不仅有助于简化复杂度,还能使应用更加灵活易扩展。
62 0
|
2月前
|
前端开发 开发者 C#
WPF开发者必读:MVVM模式实战,轻松实现现代桌面应用架构,让你的代码更上一层楼!
【8月更文挑战第31天】在WPF应用程序开发中,MVVM(Model-View-ViewModel)模式通过分离应用程序的逻辑和界面,提高了代码的可维护性和可扩展性。本文介绍了MVVM模式的三个核心组件:Model(数据模型)、View(用户界面)和ViewModel(处理数据绑定和逻辑),并通过示例代码展示了如何在WPF项目中实现MVVM模式。通过这种方式,开发者可以构建更加高效和可扩展的桌面应用程序。
59 0
|
2月前
|
设计模式 测试技术 数据处理
|
2月前
|
负载均衡 监控 JavaScript
探索微服务架构下的API网关模式
【8月更文挑战第31天】在微服务的大潮中,API网关不仅是流量的守门人,更是服务间通信的桥梁。本文将带你深入理解API网关的核心概念、设计要点及其在微服务架构中的重要作用,同时通过代码示例揭示如何利用API网关提升系统的灵活性与扩展性。
|
11天前
|
安全 应用服务中间件 API
微服务分布式系统架构之zookeeper与dubbo-2
微服务分布式系统架构之zookeeper与dubbo-2
|
11天前
|
负载均衡 Java 应用服务中间件
微服务分布式系统架构之zookeeper与dubbor-1
微服务分布式系统架构之zookeeper与dubbor-1
下一篇
无影云桌面