.NET应用架构设计—适当使用活动记录模式代替领域模型模式

简介:

阅读目录:

  • 1.背景介绍

  • 2.简单介绍领域模型模式、活动记录模式

  • 3.活动记录模式的简单示例及要点

  • 4.总结

1.背景介绍

对软件开发方法论有兴趣的博友应该发现最近“领域驱动设计”慢慢的被人发现被人实践起来,园子里也慢慢有了DDD的学习气氛和宝贵实战经验的分享。其实之前我也痴迷于DDD,为什么会痴迷于它并不是因为它是所谓的新技术,也不是因为各种对它的炒作,而是我觉得我找到了能解放我们进行企业业务系统开发的方法论。

DDD可以很好的指导我们开发可靠的软件系统,尤其是现在的企业业务复杂多变的情况下,使用DDD可以很好的随着业务变化不断的重构现有的领域模型,最为重要的是我觉得DDD是能够很好的实施敏捷价值观的软件开发方法论。

如果你想重构、测试你所写的业务代码,少不了对代码进行适当的罗动,如果没有一个好的结构让你存放你所提取出来的代码是比较无奈的。包括现在敏捷软件开发方法论中最重要的TDD方法论更加的依赖代码的结构是否能够允许进行重构,如果你的结构是很死板的,扁平化的其实很难实施TDD,你会发现你所抽象出来的概念无耻容纳。

所以我认为DDD是为了解决上述这些问题的一个好的方法,当然前提是你自己实施过之后才有资格去评判它的优劣,而且是客观公正的。

实施DDD是很费时费力的工程,没有传统的开发方法那么简单快捷,而且对开发人员的整体要求有了一个新的标准,所以本篇文章将介绍一个可以用来替代DDD模式的另外一个比较好的企业模式“活动记录模式”。

2.简单介绍领域模型模式、活动记录模式

领域模型模式其实就是领域驱动设计,两个是一个意思。有兴趣的朋友可以进一步学习领域驱动设计,我认为DDD对于一名企业应用开发人员来说是必不可少的一门设计思想,就好比设计模式一样,它也有着一套模式,用来指导我们进行相关业务场景的设计。

领域模型模式也称领域驱动设计,对业务模型进行等价的面向对象建模,无需太多考虑数据存储的技术细节,但是并不是说完全不考虑如何存储,如果谁告诉你说完全不需要考虑存储那是错误的,因为你要考虑这个领域模型最终是要如何持久化的,以免你将领域模型创建成一个巨大的蜘蛛网。说不需要考虑领域模型如何持久化其实是说你目前只需要把握领域模型创建,不去完成持久化设计细节而已,但是这两个工作往往是互相考虑的。

难道一个不懂得如何存储关系数据的人能够创建出能满足程序员很好的开发的模型吗。

活动记录模式是最靠近DDD的模式,它将数据库中的表中的一行作为自己的对象化字段,然后围绕着这些字段展开的业务逻辑,将数据字段与业务逻辑都封装在一个实例对象中。

活动记录模式与表模块模式不同的是,表模块模式是一个对象对应着一个数据库中的表,而活动记录模式是一个对象对应着一个行记录,所以称为活动记录模式。

此模式最大好处是可以基本上满足业务不是很复杂的情景下,我倒觉得活动记录模式在现在的面向SOA架构下能够更适合企业的业务系统开发团队。使用领域驱动太过于复杂,不使用又会面临着业务快速变化的困境,所以活动记录模式可以考虑试试。

3.活动记录模式的简单示例及要点

我们来看一个简单的示例,了解活动记录模式的开发及要点。

活动记录模式是使用与数据库中的表结构一直的方式使用类的,也就是说表中的列就是类的字段,当然也可以在处理业务逻辑时的辅助字段,尽量不包含多余的字段,这样可以有效保证干净的活动记录。

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
44
45
46
47
48
49
50
51
namespace  Business.RecordModels.OrderModel
{
     using  System;
     using  System.Collections.Generic;
 
     /// <summary>
     /// Order table fields.
     /// </summary>
     public  partial  class  OrderFields
     {
         /// <summary>
         /// Order id.
         /// </summary>
         public  long  OId {  get set ; }
 
         /// <summary>
         /// Order name customer declare.
         /// </summary>
         public  string  OName {  get set ; }
 
         /// <summary>
         /// Product ids.
         /// </summary>
         public  List< long > PIds {  get set ; }
 
         /// <summary>
         /// Order sum price.
         /// </summary>
         public  float  Price {  get set ; }
 
         /// <summary>
         /// Order distribute status.
         /// </summary>
         public  int  DistributeStatus {  get set ; }
 
         /// <summary>
         /// Order payment status.
         /// </summary>
         public  int  PaymentStatus {  get set ; }
 
         /// <summary>
         /// Order signer.
         /// </summary>
         public  string  Signer {  get set ; }
 
         /// <summary>
         /// Submit datetime.
         /// </summary>
         public  DateTime SubmitDt {  get set ; }
     }
}

定义一个Order活动记录的字段类,也可以直接将该字段定义在Order类中,但是一般我喜欢独立出来,因为字段一旦多了看起来实在很累。如果你想将字段直接定义在Order类中我建议你使用部分类来处理,这样比较干净。

字段中的public List<long> PIds { get; set; } 商品ID集合字段是有意聚合到该字段类中的,因为不管是业务处理还是数据持久化都是需要相关连的业务字段的。   (活动记录模式不要求你很死板的一个表一个记录实例,只要你使用你自己的方式能够让代码结构看上去很自然就是很恰当的。)

虽然你直接使用了int类型来描述业务字段,不过你可以使用其他方式让来该字段在业务处理中不直接使用语言类型而是业务概念。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace  Business.RecordModels.OrderModel
{
     /// <summary>
     /// Distribute status const.
     /// </summary>
     public  class  DistributeStatusConst
     {
         public  const  int  NoDistribute = 1;
 
         public  const  int  BeginDistribute = 2;
 
         public  const  int  EndDistribute = 3;
     }
}

配送状态常量类,定义明确的业务概念的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace  Business.RecordModels.OrderModel
{
     /// <summary>
     /// Payment status const.
     /// </summary>
     public  class  PaymentStatusConst
     {
         /// <summary>
         /// No payment.
         /// </summary>
         public  const  int  NoPayment = 1;
 
         /// <summary>
         /// End payment.
         /// </summary>
         public  const  int  EndPayment = 1;
     }
}

配送状态常量类,定义明确的业务概念的值。

对活动记录的创建我建议是用工厂来处理,毕竟这里面包含了很多业务逻辑在里面的。

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.RecordModels.OrderModel
{
     using  Common;
 
     /// <summary>
     /// Order class factory.
     /// </summary>
     public  class  OrderFactory
     {
         /// <summary>
         /// Create a order instance.
         /// </summary>
         /// <param name="fields">Order fiels instance.</param>
         /// <returns>Order instance.</returns>
         public  static  Order CreateOrder(OrderFields fields)
         {
             if  (fields.IsNull() || fields.OName.IsNullOrEmpty()
                 || fields.PIds.IsNullOrEmpty() || fields.Price.IsLessThanOrEqual0())  return  null ;
 
             fields.DistributeStatus = DistributeStatusConst.NoDistribute; //No distribute.
             fields.PaymentStatus = PaymentStatusConst.NoPayment; //No payment.
 
             return  new  Order(fields);
         }
     }
}

活动记录模式不等于没有DDD那么好,其实在业务相对不是非常复杂的情况下,活动记录模式还是相当不错的,简单快捷,对一些原子类型的字段处理使用常量就很不错。

这里我们使用DistributeStatusConst.NoDistribute、PaymentStatusConst.NoPayment 常量字段来明确的传达业务概念,而不是非要用枚举,经验告诉我有时候枚举没有常量方便。

活动记录对象中包含了该记录所表达的业务逻辑,这里的Order将包含该表所表达的业务逻辑处理。

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  Business.RecordModels.OrderModel
{
     using  System;
 
     /// <summary>
     /// Order table record
     /// </summary>
     public  partial  class  Order
     {
         /// <summary>
         /// Order table columns.
         /// </summary>
         private  OrderFields fields {  get set ; }
 
         /// <summary>
         /// New a order instance only internal use.
         /// </summary>
         /// <param name="fields">Order fields.</param>
         internal  Order(OrderFields fields)
         {
             this .fields = fields;
         }
 
         /// <summary>
         /// Calculate order expiration time.
         /// </summary>
         /// <returns>DateTime</returns>
         public  DateTime CalculateExpirationTime()
         {
             //Here you can use strategy.
             if  ( this .fields.PaymentStatus == PaymentStatusConst.NoPayment) //No payment logic
             {
                 return  this .fields.SubmitDt.AddDays(1);
             }
             else  if  ( this .fields.DistributeStatus == DistributeStatusConst.NoDistribute) //No payment logic
             {
                 return  this .fields.SubmitDt.AddDays(30);
             }
 
             return  this .fields.SubmitDt.AddDays(3);
         }
     }
}

这里我有一个简单的计算当前订单到期时间的方法(CalculateExpirationTime),在方法内部有一些业务逻辑,而该业务逻辑和当前实例一起存在。

通过使用活动记录模式可以很好的将字段与业务方法有效的集合起来,这样会使得业务逻辑处理比较有条理性,也便于测试和重构。

这里需要强调的是活动记录模式是业务层和数据层共用的模式,当时这里我们所讲的是面向业务层的,也就是说你数据层可以使用任何方式来和活动记录模式整合,现在比较流行ORM了,如果你对性能有要求你可以使用手工处理,建议使用表入口模式来结合,因为数据层没有什么逻辑,如果你的数据层有相关的逻辑我像也不会出现最后的数据源上,而是应该在数据适配层上处理掉,如:缓存、填补字段等。

4.总结

很难在一篇文章中说明所有问题,活动记录模式如果是用在读写分离大的架构中的写端时必须需要“工作单元”模式来协调多“记录”之间的事务性。但是如果你在查询端使用活动记录模式,那么大部分情况下是不需要事务性的,当然查询端我觉得使用事物脚本模式比较直观点,因为业务逻辑也不会有多少。

还是那句话,本篇文章只是分享点自己学习过程中和工作过程总结的经验,仅供参考。其实企业应用架构是一个看似简单其实很复杂的方向,希望与各位一起学习一同进步,谢谢。





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


相关文章
|
1天前
|
弹性计算 负载均衡 容灾
应用阿里云弹性计算:打造高可用性云服务器ECS架构
阿里云弹性计算助力构建高可用云服务器ECS架构,通过实例分布、负载均衡、弹性IP、数据备份及多可用区部署,确保业务连续稳定。自动容错和迁移功能进一步增强容灾能力,提供全方位高可用保障。
5 0
|
2天前
|
运维 Cloud Native 持续交付
构建未来:云原生架构在现代企业中的应用与挑战
【5月更文挑战第9天】 随着数字化转型的浪潮席卷全球,企业正迅速采纳云原生技术以实现敏捷性、可扩展性和弹性。本文深入探讨了云原生架构的关键组件,包括容器化、微服务、持续集成/持续部署(CI/CD)和DevOps文化,并分析了这些技术如何帮助企业加速产品上市时间,提高运营效率,并最终实现业务目标。同时,文章也识别了企业在采纳云原生实践中可能面临的挑战,如安全性考量、团队技能提升和复杂的网络管理,并提出了相应的解决方案和最佳实践。
|
5天前
|
监控 负载均衡 API
微服务架构在现代企业中的应用与挑战
微服务架构已成为现代企业构建灵活且可扩展软件系统的首选。然而,随着其应用的普及,企业也面临着一系列新的挑战。本篇文章将探讨微服务架构的优势、实施时遇到的问题以及解决这些问题的策略。
|
5天前
|
Kubernetes Cloud Native 持续交付
构建高效云原生应用:Kubernetes与微服务架构的融合
【5月更文挑战第6天】 在数字化转型的浪潮中,企业正迅速采纳云原生技术以实现敏捷性、可扩展性和弹性。本文深入探讨了如何利用Kubernetes这一领先的容器编排平台,结合微服务架构,构建和维护高效、可伸缩的云原生应用。通过分析现代软件设计原则和最佳实践,我们提出了一个综合指南,旨在帮助开发者和系统架构师优化云资源配置,提高部署流程的自动化水平,并确保系统的高可用性。
27 1
|
10天前
|
C# Windows
一款.NET开源、简洁易用的Windows桌面小说阅读应用
一款.NET开源、简洁易用的Windows桌面小说阅读应用
|
10天前
|
Cloud Native 安全 持续交付
构建未来:云原生架构在现代企业中的应用与挑战
【5月更文挑战第1天】 随着数字化转型的深入,云原生技术以其灵活性、可扩展性和敏捷性成为现代企业IT架构的核心。本文将探讨云原生架构的关键组件,包括容器化、微服务、持续集成/持续部署(CI/CD)以及DevOps实践,并分析它们如何共同塑造企业的运营模式。同时,文章还将讨论在采纳云原生过程中企业可能遇到的挑战,如安全性问题、技术复杂性以及组织文化的转变,并提出应对策略。
27 8
|
10天前
|
前端开发 JavaScript 安全
【TypeScript技术专栏】TypeScript在微前端架构中的应用
【4月更文挑战第30天】微前端架构通过拆分应用提升开发效率和降低维护成本,TypeScript作为静态类型语言,以其类型安全、代码智能提示和重构支持强化这一架构。在实践中,TypeScript定义公共接口确保跨微前端通信一致性,用于编写微前端以保证代码质量,且能无缝集成到构建流程中。在微前端架构中,TypeScript是保障正确性和可维护性的有力工具。
|
11天前
|
Cloud Native Devops 持续交付
构建未来应用:云原生架构在现代企业中的实践与挑战
【4月更文挑战第29天】 随着数字化转型的加速,企业正迅速转向云计算以支撑其业务敏捷性和创新。云原生技术,作为推动这一转型的关键因素,正在重新定义软件开发和运维模式。本文将深入探讨云原生架构的核心组件,包括容器化、微服务、持续集成/持续部署(CI/CD)以及DevOps文化,并分析这些技术如何帮助企业实现弹性、可扩展和高效的应用部署。同时,我们将讨论在采纳云原生实践中所面临的挑战,包括安全性、治理和人才缺口等问题。
|
12天前
|
消息中间件 PHP 数据库
【PHP开发专栏】PHP在微服务架构中的应用
【4月更文挑战第29天】微服务架构将大型应用拆分成独立小服务,PHP在其中可作为API网关、微服务提供者,参与服务发现、消息队列处理和事件驱动。最佳实践包括选择合适PHP框架、使用容器化技术、定义服务契约、采用分布式缓存、实现服务发现、监控和日志收集、优化数据库设计以及注重安全性。遵循这些实践,PHP开发者能构建高效、可扩展的微服务应用。
|
12天前
|
开发框架 物联网 测试技术
【专栏】.NET 开发:打造领先应用的基石
【4月更文挑战第29天】本文探讨了.NET开发框架为何成为构建领先应用的首选。高性能与稳定性是.NET的核心优势,它采用先进的技术和优化策略,如.NET Core的轻量级设计和JIT/AOT编译模式。跨平台兼容性让开发者能用相同代码库在不同操作系统上构建应用。现代化的开发体验,如C#语言的创新特性和Visual Studio的强大工具,提升了开发者生产力。丰富的生态系统和广泛支持,包括庞大的开发者社区和微软的持续投入,为.NET提供了坚实后盾。