阅读目录:

  • 1.背景介绍
  • 2.简单介绍领域模型模式、活动记录模式
  • 3.活动记录模式的简单示例及要点
  • 4.总结

1.背景介绍

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 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类型来描述业务字段,不过你可以使用其他方式让来该字段在业务处理中不直接使用语言类型而是业务概念。

 namespace Business.RecordModels.OrderModel
{
/// <summary>
/// Distribute status const.
/// </summary>
public class DistributeStatusConst
{
public const int NoDistribute = ; public const int BeginDistribute = ; public const int EndDistribute = ;
}
}

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

 namespace Business.RecordModels.OrderModel
{
/// <summary>
/// Payment status const.
/// </summary>
public class PaymentStatusConst
{
/// <summary>
/// No payment.
/// </summary>
public const int NoPayment = ; /// <summary>
/// End payment.
/// </summary>
public const int EndPayment = ;
}
}

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

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

 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将包含该表所表达的业务逻辑处理。

 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();
}
else if (this.fields.DistributeStatus == DistributeStatusConst.NoDistribute)//No payment logic
{
return this.fields.SubmitDt.AddDays();
} return this.fields.SubmitDt.AddDays();
}
}
}

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

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

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

4.总结

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

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

作者:王清培

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

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

.NET应用架构设计—适当使用活动记录模式代替领域模型模式的更多相关文章

  1. .NET架构设计、框架设计系列文章总结

    从事.NET开发到现在已经有七个年头了.慢慢的可能会很少写.NET文章了.不知不觉竟然走了这么多年,热爱.NET热爱c#.突然想对这一路的经历进行一个总结. 是时候开始下一阶段的旅途,希望这些文章可以 ...

  2. 架构设计 | 基于Seata中间件,微服务模式下事务管理

    源码地址:GitHub·点这里 || GitEE·点这里 一.Seata简介 1.Seata组件 Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata将为用 ...

  3. 新零售SaaS架构:中央库存系统架构设计

    近年来,越来越多的零售企业大力发展全渠道业务.在销售额增长上,通过线上的小程序.直播.平台渠道等方式,拓展流量变现渠道.在会员增长方面,通过多样的互动方式,全渠道触达消费者,扩大会员规模.而全渠道的库 ...

  4. 建筑材料系统 ASP.NET MVC4.0 + WebAPI + EasyUI + Knockout 的架构设计开发

    框架介绍: 1.基于 ASP.NET MVC4.0 + WebAPI + EasyUI + Knockout 的架构设计开发 2.采用MVC的框架模式,具有耦合性低.重用性高.生命周期成本低.可维护性 ...

  5. 架构设计 | 基于电商交易流程,图解TCC事务分段提交

    本文源码:GitHub·点这里 || GitEE·点这里 一.场景案例简介 1.场景描述 分布式事务在业务系统中是十分常见的,最经典的场景就是电商架构中的交易业务,如图: 客户端通过请求订单服务,执行 ...

  6. QQ会员活动运营平台架构设计实践——高效自动化运营

    QQ会员活动运营平台(AMS),是QQ会员增值运营业务的重要载体之一,承担海量活动运营的Web系统.在过去四年的时间里,AMS日请求量从200-500万的阶段,一直增长到日请求3-5亿,最高CGI日请 ...

  7. 架构模式数据源模式之:表数据入口(Table Data Gateway)、行数据入口(Row Data Gateway)、活动记录(Active Record)

    一:表数据入口(Table Data Gateway) 表数据入口提供了用于访问单个表或者视图(也包含了联表查询)的所有SQL,通常一个表一个类.其它代码通过它来实现对数据库的交互.基于这个特点,表数 ...

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

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

  9. MyBatis架构设计及源代码分析系列(一):MyBatis架构

    如果不太熟悉MyBatis使用的请先参见MyBatis官方文档,这对理解其架构设计和源码分析有很大好处. 一.概述 MyBatis并不是一个完整的ORM框架,其官方首页是这么介绍自己 The MyBa ...

随机推荐

  1. 【Android】《App研发录》总结

    说明 看这本书的时候,总感觉怪怪的. 因为在地铁上看完的,作者书中基本都是他自己工作中遇到的问题和坑,虽说这样会让人感觉找到了解决方案,可以再进行深入的研究,可是某些地方介绍的有点片面,仅仅是引用部分 ...

  2. ThinkPHP学习(一)

    下载3.2框架后,解压缩到web目录下面,可以看到初始的目录结构如下: 3.2版本相比之前的版本自带了一个完整的应用目录结构和默认的应用入口文件,开发人员可以在这个基 础之上灵活调整.其中, Appl ...

  3. Go项目的目录结构

    项目目录结构如何组织,一般语言都是没有规定.但Go语言这方面做了规定,这样可以保持一致性,做到统一.规则化比较明确. 1.一般的,一个Go项目在GOPATH下,会有如下三个目录: |--bin |-- ...

  4. asp.net MVC helper 和自定义函数@functions小结

    asp.net Razor 视图具有.cshtml后缀,可以轻松的实现c#代码和html标签的切换,大大提升了我们的开发效率.但是Razor语法还是有一些棉花糖值得我们了解一下,可以更加强劲的提升我们 ...

  5. Rafy 领域实体框架演示(2) - 新功能展示

    本文的演示需要先完成上一篇文章中的演示:<Rafy 领域实体框架示例(1) - 转换传统三层应用程序>.在完成改造传统的三层系统之后,本文将讲解使用 Rafy 实体框架后带来的一些常用功能 ...

  6. C#开发微信门户及应用(42)--使用Autofac实现微信接口处理的控制反转处理

    在很多情况下,我们利用IOC控制反转可以很方便实现一些接口的适配处理,可以在需要的时候切换不同的接口实现,使用这种方式在调用的时候,只需要知道相应的接口接口,具体调用哪个实现类,可以在配置文件中动态指 ...

  7. webapi文档描述-swagger

    最近做的项目使用mvc+webapi,采取前后端分离的方式,后台提供API接口给前端开发人员.这个过程中遇到一个问题后台开发人员怎么提供接口说明文档给前端开发人员,最初打算使用word文档方式进行交流 ...

  8. 关于项目中值对象Identifier的设计-领域驱动

    到现在为止做了不项目,发现每个实体都会有个相应的值对象. 先简单说一下值对象和实体之间的区别: (以下内容来着<领域驱动设计>一书) 当一个小孩画画的时候,他注意的是画笔的颜色和笔尖的粗细 ...

  9. 【转】mysql的union、left join、 right join、 inner join和视图学习

    1.联合 union 进行多个查询语句时,要求多次查询的结果列数必须一样.此时,查询的结果以第一个sql语句的列名为准且union会自动去重复我们应该使用union all. 例...... 1.联合 ...

  10. 个人项目框架搭建 -- Autofac简单使用记录

    1.添加autofac相关程序集/使用Nuget 2.引入命名空间 using Autofac; using Autofac.Configuration; 3.使用 3.1:直接使用 var buil ...