.NET应用架构设计—表模块模式与事务脚本模式的代码编写

简介:

阅读目录:

  • 1.背景介绍

  • 2.简单介绍表模块模式、事务脚本模式

  • 3.正确的编写表模块模式、事务脚本模式的代码

  • 4.总结

1.背景介绍

要想正确的设计系统架构就必须能正确的搞懂每个架构模式的用意,而不是胡子眉毛一把抓。现在有一个现象是什么呢,项目的结构从表面上看是很不错,层分的很合理,其实对业务系统来说也就那么几种层设计方法,但是现在很多项目的逻辑架构的设计不是理想,有很多概念大家并不是很了解,当然也许每个人对技术的追求不同罢了。不管你追求不追求,事实我们还是要去往正确的方向努力才对的。

很多人包括我自己在内,都是写过很多年的过程式的代码,层对我当年来说就是个摆设而已,最典型的问题就是我们总是将表模块模式和事物脚本模式一起混着使用,什么意思呢,就是说我们都会使用一些代码生成器来根据数据库中的表来生成三层架构中的业务层和数据层,有些比较好的代码生成器也可以帮你把UI层中的部分视图也生成好,确实很强大,有些场合下这是一中最合适的过程。

但是现在的系统已经不在是那样的了,其中重要的一点就是业务复杂了,如果我们还稀里糊涂的编写着代码,最后只会成为你或者团队的技术债务。

2.简单介绍表模块模式、事务脚本模式

我们简单了解一下这里所谓的“表模块模式、”事务脚本模式“到底是什么样子的模式,最关键是你也许就知道了你目前所使用的业务层架构风格是什么模式,强调一下“表模块模式”、“事物脚本模式”都是业务层的构架模式。

表模块模式:

简单讲就是你数据库中的每个表对应着业务层中的一个对象定义,如果你有一个Product表,那么你在Business Layer中就有一个Product.cs文件,当然这不是绝对的,你也可以将库中的视图也定义一个类型,如,OrderProduct.cs,也是可以的。然后每个类中的所处理的逻辑都是跟这张表相关的,你在Product.cs中的代码就不要包含Order.cs中的代码了。目前来看是有的,因为现在大部分的项目都是在写着使用过程式的代码,也就是事物脚本模式,这样难免会将其他类型中的代码写到本类中。

事物脚本模式:

事务脚本模式就是过程式的代码,只不过它的指标就是每一个代码段独立完成一个业务单元,而不是到处都是过程代码,事物脚本模式还是很强调逻辑的统一性的。

使用此模式进行写代码时,你就不要单纯的使用数据库中的表名来定义业务类了,因为你是使用事务脚本模式的,你需要站在业务角度来规划你的业务层中大概包含哪些业务概念,然后使用这个业务概念来命名你的类。比如:UserOrder,UserOrder,类似这样的定义,当然这里只是个假设而已,你不要站在数据库的脚本来设计业务层就行了,这样你就起码不会使用到很细粒度的类型,哪怕下一次迭代进行重构也是可以的。

3.正确的编写表模块模式、事务脚本模式的代码

这篇文章的重点就是本节,我们将了解一下这两种模式的代码到底该如何编写。

说代码如何编写似乎有点让人觉得不是很礼貌,其实我们大部分的代码写的都是正确的,但是如果我们将有些代码稍微的罗一下位置就会明显不一样。

我们来看一个小例子,例子很简单,有两个类型Order、Product,用来完成一般的业务逻辑处理,我们通过不同的模式来看到底如何使用。

现在的事务脚本模式的代码:

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
namespace  Business
{
     public  class  Order
     {
         [Serializable]
         public  class  OrderField
         {
             public  string  OId {  get set ; }
[NonSerialized]
             public 
List<Product.ProductField> Products {  get set ; }
         }
public  OrderField Field {  get set ; }
public  void  AddOrder(OrderField orderField)
         {
             var  sendMQOrders =  new  List< string >(); //合格的产品ID集合
orderField.Products.ForEach(product =>
             {
                 if  (product.Price <= 20) //不满足条件
                     return ;
sendMQOrders.Add(product.PId); //满足条件
             });
MqHelper.SendOrder(orderField, 
sendMQOrders); //发送订单数据实体到队列中
         }
     }
}

Order业务类中有一个添加Order的方法,在该方法中是一些简单的业务逻辑处理,判断了要添加的这个商品的价格是否大于20块钱。最后使用过滤下来的商品ID作为本订单的有效产品。

这就是我们目前使用的代码风格,这里有两个问题,第一:类的命名,Order的概念太大了,没有进行细化,显然不是按照事务脚本模式来进行设计的而是按照表模块方式进行划分的,还有如果我就算你是按照事物脚本模式来设计的,我就喜欢定义大的概念难道不对吗?也可以,但是在Order的定义里面明确使用了Product类型下的子类型,也就说这里出现了两个独立的业务范围,正常的理解肯定是按照表模块模式来设计的。第二:如果是按照表模块模式来设计的,因为根据这个对象的命名很明显是此模式,但是仔细阅读一下代码发现职责还是有点不清晰,在Order.AddOrder(OrderField orderField)方法中,有Product的逻辑在里面if (product.Price <= 20),当然这里是业务逻辑比较简单的情况下的,如果是业务比较复杂的时候,就会出现大量的代码在Order类中,到最后就会发现我们已经分不清此业务架构到底是使用何种模式来设计的。

我们有两个做法,第一个做法是:将其改成事务脚本模式,让类的命名和设计泛化,也就是说不要定义那么明显的数据库中的表名字,不要清晰的区分Order和Product两个职责。第二个做法是:将其改成表模块模式,将每个类型中的业务逻辑完全清晰化,将if (product.Price <= 20)提取到Product业务类中去,然后在应用控制器中先处理此逻辑后在调用Order.AddOrder(OrderField orderField)方法进行处理,这个方法里面只做跟当前类型相关的逻辑,参考的依据就是一旦你发现你所写的代码里出现了别的类型时,此时你应该告诉自己有可能这个地方需要重构职责。

两个方法来移动此逻辑:

1:(将if (product.Price <= 20)封进Price属性中)

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
namespace  Business
{
     public  class  Order
     {
         [Serializable]
         public  class  OrderField
         {
             public  string  OId {  get set ; }
[NonSerialized]
             public 
List<Product.ProductField> Products {  get set ; }
         }
public  OrderField Field {  get set ; }
public  void  AddOrder(OrderField orderField)
         {
             var  sendMQOrders =  new  List< string >(); //合格的产品ID集合
orderField.Products.ForEach(product =>
             {
                 if  (product.Price.IsValid() /*执行价格判断*/ return ;
sendMQOrders.Add(product.PId); //满足条件
             });
MqHelper.SendOrder(orderField, 
sendMQOrders); //发送订单数据实体到队列中
         }
     }
}

此方法有个问题就是商品的价格没有收到订单的控制,这看具体的业务需要了,我只是个假设。

2:完全独立的过滤无效产品的方法

1
2
3
4
5
6
7
8
9
10
11
12
namespace  Business
{
     public  class  OrderApplicationController
     {
         public  void  SubmitOrder(Order.OrderField field)
         {
             field.Products =  new 
Product().FilterProduct(field.Products); //先过滤
new  Order().AddOrder(field); //在添加
         }
     }
}

我们先调用Product中的业务方法过滤无效的商品,然后在进行订单添加操作,这样我们就将各自的职责放到自己的位置去。

4.总结

还是那句话,这只是我学习过程中的一点小小的领悟,给大家一个参考的资料,希望对你有用,谢谢。




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


相关文章
|
9天前
|
机器学习/深度学习 存储 编解码
RT-DETR改进策略【Neck】| ArXiv 2023,基于U - Net v2中的的高效特征融合模块:SDI(Semantics and Detail Infusion)
RT-DETR改进策略【Neck】| ArXiv 2023,基于U - Net v2中的的高效特征融合模块:SDI(Semantics and Detail Infusion)
42 16
RT-DETR改进策略【Neck】| ArXiv 2023,基于U - Net v2中的的高效特征融合模块:SDI(Semantics and Detail Infusion)
|
11天前
|
机器学习/深度学习 存储 编解码
YOLOv11改进策略【Neck】| ArXiv 2023,基于U - Net v2中的的高效特征融合模块:SDI(Semantics and Detail Infusion)
YOLOv11改进策略【Neck】| ArXiv 2023,基于U - Net v2中的的高效特征融合模块:SDI(Semantics and Detail Infusion)
38 7
YOLOv11改进策略【Neck】| ArXiv 2023,基于U - Net v2中的的高效特征融合模块:SDI(Semantics and Detail Infusion)
|
1月前
|
C# Android开发 iOS开发
2025年全面的.NET跨平台应用框架推荐
2025年全面的.NET跨平台应用框架推荐
86 23
|
2月前
|
存储 NoSQL MongoDB
.NET MongoDB数据仓储和工作单元模式封装
.NET MongoDB数据仓储和工作单元模式封装
59 15
|
2月前
|
算法 Java 测试技术
使用 BenchmarkDotNet 对 .NET 代码进行性能基准测试
使用 BenchmarkDotNet 对 .NET 代码进行性能基准测试
66 13
|
2月前
|
开发框架 .NET PHP
ASP.NET Web Pages - 添加 Razor 代码
ASP.NET Web Pages 使用 Razor 标记添加服务器端代码,支持 C# 和 Visual Basic。Razor 语法简洁易学,类似于 ASP 和 PHP。例如,在网页中加入 `@DateTime.Now` 可以实时显示当前时间。
|
3月前
|
敏捷开发 缓存 中间件
.NET技术的高效开发模式,涵盖面向对象编程、良好架构设计及高效代码编写与管理三大关键要素
本文深入探讨了.NET技术的高效开发模式,涵盖面向对象编程、良好架构设计及高效代码编写与管理三大关键要素,并通过企业级应用和Web应用开发的实践案例,展示了如何在实际项目中应用这些模式,旨在为开发者提供有益的参考和指导。
53 3
|
3月前
|
开发框架 监控 .NET
【Azure App Service】部署在App Service上的.NET应用内存消耗不能超过2GB的情况分析
x64 dotnet runtime is not installed on the app service by default. Since we had the app service running in x64, it was proxying the request to a 32 bit dotnet process which was throwing an OutOfMemoryException with requests >100MB. It worked on the IaaS servers because we had the x64 runtime install
|
3月前
|
JSON 算法 安全
JWT Bearer 认证在 .NET Core 中的应用
【10月更文挑战第30天】JWT(JSON Web Token)是一种开放标准,用于在各方之间安全传输信息。它由头部、载荷和签名三部分组成,用于在用户和服务器之间传递声明。JWT Bearer 认证是一种基于令牌的认证方式,客户端在请求头中包含 JWT 令牌,服务器验证令牌的有效性后授权用户访问资源。在 .NET Core 中,通过安装 `Microsoft.AspNetCore.Authentication.JwtBearer` 包并配置认证服务,可以实现 JWT Bearer 认证。具体步骤包括安装 NuGet 包、配置认证服务、启用认证中间件、生成 JWT 令牌以及在控制器中使用认证信息
176 2
|
4月前
|
网络协议 大数据 网络架构
桥接模式和NET模式的区别
桥接模式和NET模式的区别
75 0

热门文章

最新文章