阅读目录:程序员
对软件开发方法论有兴趣的博友应该发现最近“领域驱动设计”慢慢的被人发现被人实践起来,园子里也慢慢有了DDD的学习气氛和宝贵实战经验的分享。其实以前我也痴迷于DDD,为何会痴迷于它并非由于它是所谓的新技术,也不是由于各类对它的炒做,而是我以为我找到了能解放咱们进行企业业务系统开发的方法论。数据库
DDD能够很好的指导咱们开发可靠的软件系统,尤为是如今的企业业务复杂多变的状况下,使用DDD能够很好的随着业务变化不断的重构现有的领域模型,最为重要的是我以为DDD是可以很好的实施敏捷价值观的软件开发方法论。设计模式
若是你想重构、测试你所写的业务代码,少不了对代码进行适当的罗动,若是没有一个好的结构让你存放你所提取出来的代码是比较无奈的。包括如今敏捷软件开发方法论中最重要的TDD方法论更加的依赖代码的结构是否可以容许进行重构,若是你的结构是很死板的,扁平化的其实很难实施TDD,你会发现你所抽象出来的概念无耻容纳。缓存
因此我认为DDD是为了解决上述这些问题的一个好的方法,固然前提是你本身实施过以后才有资格去评判它的优劣,并且是客观公正的。架构
实施DDD是很费时费力的工程,没有传统的开发方法那么简单快捷,并且对开发人员的总体要求有了一个新的标准,因此本篇文章将介绍一个能够用来替代DDD模式的另一个比较好的企业模式“活动记录模式”。性能
领域模型模式其实就是领域驱动设计,两个是一个意思。有兴趣的朋友能够进一步学习领域驱动设计,我认为DDD对于一名企业应用开发人员来讲是必不可少的一门设计思想,就比如设计模式同样,它也有着一套模式,用来指导咱们进行相关业务场景的设计。学习
领域模型模式也称领域驱动设计,对业务模型进行等价的面向对象建模,无需太多考虑数据存储的技术细节,可是并非说彻底不考虑如何存储,若是谁告诉你说彻底不须要考虑存储那是错误的,由于你要考虑这个领域模型最终是要如何持久化的,以避免你将领域模型建立成一个巨大的蜘蛛网。说不须要考虑领域模型如何持久化实际上是说你目前只须要把握领域模型建立,不去完成持久化设计细节而已,可是这两个工做每每是互相考虑的。测试
难道一个不懂得如何存储关系数据的人可以建立出能知足程序员很好的开发的模型吗。this
活动记录模式是最靠近DDD的模式,它将数据库中的表中的一行做为本身的对象化字段,而后围绕着这些字段展开的业务逻辑,将数据字段与业务逻辑都封装在一个实例对象中。spa
活动记录模式与表模块模式不一样的是,表模块模式是一个对象对应着一个数据库中的表,而活动记录模式是一个对象对应着一个行记录,因此称为活动记录模式。
此模式最大好处是能够基本上知足业务不是很复杂的情景下,我倒以为活动记录模式在如今的面向SOA架构下可以更适合企业的业务系统开发团队。使用领域驱动太过于复杂,不使用又会面临着业务快速变化的困境,因此活动记录模式能够考虑试试。
咱们来看一个简单的示例,了解活动记录模式的开发及要点。
活动记录模式是使用与数据库中的表结构一直的方式使用类的,也就是说表中的列就是类的字段,固然也能够在处理业务逻辑时的辅助字段,尽可能不包含多余的字段,这样能够有效保证干净的活动记录。
1 namespace Business.RecordModels.OrderModel 2 { 3 using System; 4 using System.Collections.Generic; 5 6 /// <summary> 7 /// Order table fields. 8 /// </summary> 9 public partial class OrderFields 10 { 11 /// <summary> 12 /// Order id. 13 /// </summary> 14 public long OId { get; set; } 15 16 /// <summary> 17 /// Order name customer declare. 18 /// </summary> 19 public string OName { get; set; } 20 21 /// <summary> 22 /// Product ids. 23 /// </summary> 24 public List<long> PIds { get; set; } 25 26 /// <summary> 27 /// Order sum price. 28 /// </summary> 29 public float Price { get; set; } 30 31 /// <summary> 32 /// Order distribute status. 33 /// </summary> 34 public int DistributeStatus { get; set; } 35 36 /// <summary> 37 /// Order payment status. 38 /// </summary> 39 public int PaymentStatus { get; set; } 40 41 /// <summary> 42 /// Order signer. 43 /// </summary> 44 public string Signer { get; set; } 45 46 /// <summary> 47 /// Submit datetime. 48 /// </summary> 49 public DateTime SubmitDt { get; set; } 50 } 51 }
定义一个Order活动记录的字段类,也能够直接将该字段定义在Order类中,可是通常我喜欢独立出来,由于字段一旦多了看起来实在很累。若是你想将字段直接定义在Order类中我建议你使用部分类来处理,这样比较干净。
字段中的public List<long> PIds { get; set; } 商品ID集合字段是有意聚合到该字段类中的,由于不论是业务处理仍是数据持久化都是须要相关连的业务字段的。 (活动记录模式不要求你很死板的一个表一个记录实例,只要你使用你本身的方式可以让代码结构看上去很天然就是很恰当的。)
虽然你直接使用了int类型来描述业务字段,不过你可使用其余方式让来该字段在业务处理中不直接使用语言类型而是业务概念。
1 namespace Business.RecordModels.OrderModel 2 { 3 /// <summary> 4 /// Distribute status const. 5 /// </summary> 6 public class DistributeStatusConst 7 { 8 public const int NoDistribute = 1; 9 10 public const int BeginDistribute = 2; 11 12 public const int EndDistribute = 3; 13 } 14 }
配送状态常量类,定义明确的业务概念的值。
1 namespace Business.RecordModels.OrderModel 2 { 3 /// <summary> 4 /// Payment status const. 5 /// </summary> 6 public class PaymentStatusConst 7 { 8 /// <summary> 9 /// No payment. 10 /// </summary> 11 public const int NoPayment = 1; 12 13 /// <summary> 14 /// End payment. 15 /// </summary> 16 public const int EndPayment = 1; 17 } 18 }
配送状态常量类,定义明确的业务概念的值。
对活动记录的建立我建议是用工厂来处理,毕竟这里面包含了不少业务逻辑在里面的。
1 namespace Business.RecordModels.OrderModel 2 { 3 using Common; 4 5 /// <summary> 6 /// Order class factory. 7 /// </summary> 8 public class OrderFactory 9 { 10 /// <summary> 11 /// Create a order instance. 12 /// </summary> 13 /// <param name="fields">Order fiels instance.</param> 14 /// <returns>Order instance.</returns> 15 public static Order CreateOrder(OrderFields fields) 16 { 17 if (fields.IsNull() || fields.OName.IsNullOrEmpty() 18 || fields.PIds.IsNullOrEmpty() || fields.Price.IsLessThanOrEqual0()) return null; 19 20 fields.DistributeStatus = DistributeStatusConst.NoDistribute;//No distribute. 21 fields.PaymentStatus = PaymentStatusConst.NoPayment;//No payment. 22 23 return new Order(fields); 24 } 25 } 26 }
活动记录模式不等于没有DDD那么好,其实在业务相对不是很是复杂的状况下,活动记录模式仍是至关不错的,简单快捷,对一些原子类型的字段处理使用常量就很不错。
这里咱们使用DistributeStatusConst.NoDistribute、PaymentStatusConst.NoPayment 常量字段来明确的传达业务概念,而不是非要用枚举,经验告诉我有时候枚举没有常量方便。
活动记录对象中包含了该记录所表达的业务逻辑,这里的Order将包含该表所表达的业务逻辑处理。
1 namespace Business.RecordModels.OrderModel 2 { 3 using System; 4 5 /// <summary> 6 /// Order table record 7 /// </summary> 8 public partial class Order 9 { 10 /// <summary> 11 /// Order table columns. 12 /// </summary> 13 private OrderFields fields { get; set; } 14 15 /// <summary> 16 /// New a order instance only internal use. 17 /// </summary> 18 /// <param name="fields">Order fields.</param> 19 internal Order(OrderFields fields) 20 { 21 this.fields = fields; 22 } 23 24 /// <summary> 25 /// Calculate order expiration time. 26 /// </summary> 27 /// <returns>DateTime</returns> 28 public DateTime CalculateExpirationTime() 29 { 30 //Here you can use strategy. 31 if (this.fields.PaymentStatus == PaymentStatusConst.NoPayment)//No payment logic 32 { 33 return this.fields.SubmitDt.AddDays(1); 34 } 35 else if (this.fields.DistributeStatus == DistributeStatusConst.NoDistribute)//No payment logic 36 { 37 return this.fields.SubmitDt.AddDays(30); 38 } 39 40 return this.fields.SubmitDt.AddDays(3); 41 } 42 } 43 }
这里我有一个简单的计算当前订单到期时间的方法(CalculateExpirationTime),在方法内部有一些业务逻辑,而该业务逻辑和当前实例一块儿存在。
经过使用活动记录模式能够很好的将字段与业务方法有效的集合起来,这样会使得业务逻辑处理比较有条理性,也便于测试和重构。
这里须要强调的是活动记录模式是业务层和数据层共用的模式,当时这里咱们所讲的是面向业务层的,也就是说你数据层可使用任何方式来和活动记录模式整合,如今比较流行ORM了,若是你对性能有要求你可使用手工处理,建议使用表入口模式来结合,由于数据层没有什么逻辑,若是你的数据层有相关的逻辑我像也不会出现最后的数据源上,而是应该在数据适配层上处理掉,如:缓存、填补字段等。
很难在一篇文章中说明全部问题,活动记录模式若是是用在读写分离大的架构中的写端时必须须要“工做单元”模式来协调多“记录”之间的事务性。可是若是你在查询端使用活动记录模式,那么大部分状况下是不须要事务性的,固然查询端我以为使用事物脚本模式比较直观点,由于业务逻辑也不会有多少。
仍是那句话,本篇文章只是分享点本身学习过程当中和工做过程总结的经验,仅供参考。其实企业应用架构是一个看似简单其实很复杂的方向,但愿与各位一块儿学习一同进步,谢谢。