DDD领域驱动设计之聚合、实体、值对象
关于具体需求,请看前面的博文:DDD领域驱动设计实践篇之如何提取模型,下面是具体的实体、聚合、值对象的代码,不想多说什么是实体、聚合等概念,相信理论的东西大家已经知晓了。本人对DDD表示好奇,没有在真正项目实践过,甚至也没有看过真正的DDD实践的项目源码,处于极度纠结状态,甚至无法自拔,所以告诫DDD爱好者们,如果要在项目里面实践DDD,除非你对实体建模和领域职责非常了解(很多时候会纠结一些逻辑放哪里好,属于设计问题)以及你的团队水平都比较高认同DDD,否则请慎重。。。勿喷!
代码在后,请先看DEMO结果图



1、聚合的基类,注意,几乎属性都是拼音首字母命名,勿喷哈,不要跑题!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DDD.Infrastructure;
using DDD.Infrastructure.Domain; namespace DDD.Domain
{
/// <summary>
/// 项目基类
/// </summary>
public abstract class ProjectBase : EntityBase, IAggregateRoot
{
protected ProjectBase()
{
this.ND = DateTime.Now.Year;
this.CJSJ = DateTime.Now;
this.WH = new DocumentNumber();
} /// <summary>
/// 安排批次
/// </summary>
public int APPC { get; set; }
/// <summary>
/// 项目名称
/// </summary>
public string XMMC { get; set; }
/// <summary>
/// 项目编号
/// </summary>
public string XMBH { get; internal set; }
/// <summary>
/// 年度
/// </summary>
public int ND { get; set; }
/// <summary>
/// 文号
/// </summary>
public DocumentNumber WH { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CJSJ { get; set; }
/// <summary>
/// 下发行政区名称
/// </summary>
public string XFXZQMC { get; set; }
/// <summary>
/// 下发行政区代码
/// </summary>
public string XFXZQDM { get; set; }
/// <summary>
/// 行政区名称
/// </summary>
public string XZQMC { get; set; }
/// <summary>
/// 行政区代码
/// </summary>
public string XZQDM { get; set; }
/// <summary>
/// 备注
/// </summary>
public string BZ { get; set; }
/// <summary>
/// 指标级别
/// </summary>
public IndicatorGrade ZBJB { get; set; }
/// <summary>
/// 附件id
/// </summary>
public decimal ATTACHID { get; set; }
/// <summary>
/// 项目状态
/// </summary>
public ProjectStauts Status { get; set; } /// <summary>
/// 业务代码
/// </summary>
protected abstract string BussinessCode { get; } /// <summary>
/// 登记
/// </summary>
/// <param name="seq"></param>
public virtual void Register()
{
this.XMBH = this.BussinessCode + SeqGeneratr.Generate();
} /// <summary>
/// 是否可以更新或者删除
/// </summary>
/// <returns></returns>
public virtual bool CanUpdate()
{
return this.ZBJB == IndicatorGrade.Country || this.XFXZQDM == this.XZQDM || this.Status == ProjectStauts.Default;
} public void Send()
{
this.Status = ProjectStauts.Sent;
}
}
}
2、聚合1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DDD.Infrastructure;
using DDD.Infrastructure.Domain; namespace DDD.Domain.Indicator
{
/// <summary>
/// 计划指标
/// </summary>
public class PlanIndicator : ProjectBase
{
public PlanIndicator()
{
IndicatorArea = new IndicatorArea();
} protected override string BussinessCode
{
get { return "103101"; }
} /// <summary>
/// 指标面积
/// </summary>
public IndicatorArea IndicatorArea
{
get;
set;
} public override IEnumerable<BusinessRule> Validate()
{
if (this.IndicatorArea.GD > this.IndicatorArea.NYD)
{
yield return new BusinessRule("IndicatorArea.GD", "耕地面积不能大于农用地面积");
}
} public override void Register()
{
if (this.ZBJB == IndicatorGrade.Country)
{
this.Send();
}
base.Register();
}
}
}
3、聚合2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DDD.Infrastructure;
using DDD.Infrastructure.Domain; namespace DDD.Domain.Arrange
{
/// <summary>
/// 计划安排
/// </summary>
public class PlanArrange : ProjectBase
{
public PlanArrange()
{
JHSY = new IndicatorArea();
SJSY = new IndicatorArea();
} protected override string BussinessCode
{
get { return "103102"; }
} /// <summary>
/// 计划使用面积
/// </summary>
public IndicatorArea JHSY
{
get;
set;
} /// <summary>
/// 实际使用面积
/// </summary>
public IndicatorArea SJSY
{
get;
set;
} /// <summary>
/// 剩余面积
/// </summary>
public IndicatorArea SY
{
get
{
return JHSY - SJSY;
}
} /// <summary>
/// 用地类别
/// </summary>
public string XMYDLB { get; set; } public override IEnumerable<BusinessRule> Validate()
{
if (this.JHSY.GD > this.JHSY.NYD)
{
yield return new BusinessRule("JHSY.GD", "计划使用中,耕地面积不能大于农用地面积");
}
if (this.SJSY.GD > this.SJSY.NYD)
{
yield return new BusinessRule("SJSY.GD", "实际使用中,耕地面积不能大于农用地面积");
}
if (string.IsNullOrEmpty(this.XMYDLB))
{
yield return new BusinessRule("XMYDLB", "项目用地类别不允许为空");
}
}
}
}
4、值对象1
using System;
using DDD.Infrastructure.Domain; namespace DDD.Domain
{
/// <summary>
/// 文号
/// </summary>
public class DocumentNumber : ValueObject<DocumentNumber>, ICloneable
{
public static readonly string LeftYearChar = "〔";
public static readonly string RightYearChar = "〕"; public DocumentNumber()
{ } public DocumentNumber(string wh)
{
try
{
this.Code = wh.Substring(0, wh.IndexOf(LeftYearChar));
this.Year = wh.Substring(wh.IndexOf(LeftYearChar), wh.IndexOf(RightYearChar) - this.Code.Length + 1);
this.Order = wh.Replace(this.Code + this.Year, "");
this.Year = this.Year.Replace(LeftYearChar, "").Replace(RightYearChar, "");
}
catch(Exception ex)
{
throw new InvalidCastException("文号格式不正确", ex);
}
} /// <summary>
/// 发文机关代字
/// </summary>
public string Code { get; set; }
/// <summary>
/// 年份
/// </summary>
public string Year { get; set; }
private string order;
/// <summary>
/// 顺序号
/// </summary>
public string Order
{
get
{
if (!string.IsNullOrEmpty(order) && !order.Contains("号"))
{
order += "号";
}
return order;
}
set
{
order = value;
}
} public override string ToString()
{
if (string.IsNullOrEmpty(Code) && string.IsNullOrEmpty(Year) && string.IsNullOrEmpty(order))
{
return string.Empty;
}
return this.Code + LeftYearChar + Year + RightYearChar + Order;
} public static implicit operator DocumentNumber(string wh)
{
return new DocumentNumber(wh);
} public object Clone()
{
return this.MemberwiseClone();
}
}
}
5、值对象2
using DDD.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DDD.Infrastructure.Domain; namespace DDD.Domain
{
/// <summary>
/// 指标面积
/// </summary>
public class IndicatorArea : ValueObject<IndicatorArea>
{
/// <summary>
/// 新增建设用地
/// </summary>
public decimal XZJSYD
{
get
{
return NYD + WLYD;
}
}
/// <summary>
/// 农用地
/// </summary>
public decimal NYD { get; set; }
/// <summary>
/// 耕地
/// </summary>
public decimal GD { get; set; }
/// <summary>
/// 未利用地
/// </summary>
public decimal WLYD { get; set; } /// <summary>
/// 将公顷转换成亩
/// </summary>
/// <returns></returns>
public IndicatorArea HectareToMu()
{
return new IndicatorArea
{
GD = this.GD * 15,
NYD = this.NYD * 15,
WLYD = this.WLYD * 15,
};
} /// <summary>
/// 重载加法运算符
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static IndicatorArea operator +(IndicatorArea a, IndicatorArea b)
{
return new IndicatorArea
{
GD = a.GD + b.GD,
NYD = a.NYD + b.NYD,
WLYD = a.WLYD + b.WLYD,
};
} /// <summary>
/// 重载减法运算符
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static IndicatorArea operator -(IndicatorArea a, IndicatorArea b)
{
return new IndicatorArea
{
GD = a.GD - b.GD,
NYD = a.NYD - b.NYD,
WLYD = a.WLYD - b.WLYD,
};
} public static IndicatorArea Sum(IEnumerable<IndicatorArea> query)
{
return new IndicatorArea
{
GD = query.Sum(t => t.GD),
NYD = query.Sum(t => t.NYD),
WLYD = query.Sum(t => t.WLYD),
};
}
}
}
6、枚举
using System.ComponentModel; namespace DDD.Domain
{
/// <summary>
/// 指标级别
/// </summary>
public enum IndicatorGrade
{
/// <summary>
/// 国家
/// </summary>
[Description("国家")]
Country,
/// <summary>
/// 省级
/// </summary>
[Description("省级")]
Province,
/// <summary>
/// 市级
/// </summary>
[Description("市级")]
City,
/// <summary>
/// 县级
/// </summary>
[Description("县级")]
County,
}
}
using System.ComponentModel; namespace DDD.Domain
{
/// <summary>
/// 项目状态
/// </summary>
public enum ProjectStauts
{
/// <summary>
/// 默认状态,已登记
/// </summary>
Default,
/// <summary>
/// 已下发
/// </summary>
Sent,
}
}
DDD领域驱动设计之聚合、实体、值对象的更多相关文章
- DDD领域驱动设计之领域服务
1.DDD领域驱动设计实践篇之如何提取模型 2.DDD领域驱动设计之聚合.实体.值对象 3.DDD领域驱动设计之领域基础设施层 什么是领域服务,DDD书中是说,有些类或者方法,放实体A也不好,放实体B ...
- DDD领域驱动设计之领域基础设施层
1.DDD领域驱动设计实践篇之如何提取模型 2.DDD领域驱动设计之聚合.实体.值对象 其实这里说的基础设施层只是领域层的一些接口和基类而已,没有其他的如日子工具等代码,仅仅是为了说明领域层的一些基础 ...
- DDD领域驱动设计之运用层代码
1.DDD领域驱动设计实践篇之如何提取模型 2.DDD领域驱动设计之聚合.实体.值对象 3.DDD领域驱动设计之领域基础设施层 4.DDD领域驱动设计之领域服务 5.整体DEMO代码 什么是运用层,说 ...
- DDD 领域驱动设计-三个问题思考实体和值对象(续)
上一篇:DDD 领域驱动设计-三个问题思考实体和值对象 说实话,整理现在这一篇博文的想法,在上一篇发布出来的时候就有了,但到现在才动起笔来,而且写之前又反复读了上一篇博文的内容及评论,然后去收集资料, ...
- DDD 领域驱动设计-三个问题思考实体和值对象
消息场景:用户 A 发送一个消息给用户 B,用户 B 回复一个消息给用户 A... 现有设计:消息设计为实体并为聚合根,发件人.收件人设计为值对象. 三个问题: 实体最重要的特性是什么? Messag ...
- DDD 领域驱动设计-“臆想”中的实体和值对象
其他博文: DDD 领域驱动设计-三个问题思考实体和值对象 DDD 领域驱动设计-三个问题思考实体和值对象(续) 以下内容属于博主"臆想",如有不当,请别当真. 扯淡开始: 诺兰的 ...
- C#进阶系列——DDD领域驱动设计初探(一):聚合
前言:又有差不多半个月没写点什么了,感觉这样很对不起自己似的.今天看到一篇博文里面写道:越是忙人越有时间写博客.呵呵,似乎有点道理,博主为了证明自己也是忙人,这不就来学习下DDD这么一个听上去高大上的 ...
- DDD领域驱动设计初探(一):聚合
前言:又有差不多半个月没写点什么了,感觉这样很对不起自己似的.今天看到一篇博文里面写道:越是忙人越有时间写博客.呵呵,似乎有点道理,博主为了证明自己也是忙人,这不就来学习下DDD这么一个听上去高大上的 ...
- DDD 领域驱动设计-两个实体的碰撞火花
上一篇:<DDD 领域驱动设计-领域模型中的用户设计?> 开源地址:https://github.com/yuezhongxin/CNBlogs.Apply.Sample(代码已更新) 在 ...
随机推荐
- Python list列表的排序
当我们从数据库中获取一写数据后,一般对于列表的排序是经常会遇到的问题,今天总结一下python对于列表list排序的常用方法: 第一种:内建函数sort() 这个应该是我们使用最多的也是最简单的排序函 ...
- C、C++、Java、go的语法区别
详细C++.Java比较:http://www.cnblogs.com/stephen-liu74/archive/2011/07/27/2118660.html 一.C.C++的区别 在很大程度上, ...
- css3选择器总结
1.p[class^/$/*=td]所有p标签的前面带有td/后面带有td/所有带有td的类的三种样式. 2.div:first-child/last-child/nth-child()在父元素下的第 ...
- java 读取文件内容 三种形式及效率对比
IOUtils.getStringFromReader() 读取方式为最快的 InputStream in = null; String line = ""; long start ...
- Android Application类作用简单说明
每个程序运行时创建一个Application类的对象且只创建一个 Application对象的生命周期是整个程序中最长的,它的生命周期就等于这个程序的生命周期. Application来进行一些,如: ...
- PerconaXtraBackup 压缩备份集
压缩备份集 stream模式支持且只支持:tar 和 xbstream 两种格式,后者是xtrabackup提供的专有格式,解包时需要同名的专用命令处理 innobackupex --defaults ...
- 如何编写高效的jQuery代码
jQuery的编写原则: 一.不要过度使用jQuery 1. jQuery速度再快,也无法与原生的javascript方法相比,而且建立的jQuery对象包含的信息量很庞大.所以有原生方法可以使用的场 ...
- 『TCP/IP详解——卷一:协议』读书笔记——18
2013-08-27 15:44:52 第7章 Ping程序 7.1 引言 “ping”这个名字来源于声纳定为操作.Ping程序由Mike Muuss编写,目的是为了测试另一台主机是否可达.该程序发送 ...
- [UE4]CustomAnimationBlueprintNode 自定义动画蓝图节点
目的:在AnimationBlueprint中使用自定义动画控制节点. 主要过程: 1. 引用相关模块.在Client.Build.cs文件中,PublicDependencyModuleN ...
- javascript基础知识-函数
1.javascript中函数有两种定义方式: 函数语句定义和表达式定义 //函数有定义 function test(){ console.log("This is a function&q ...