结合领域驱动设计的SOA分布式软件架构,你还在为这些烦恼?( 二 )
值对象:当所用到的对象只有属性而没有其他逻辑关系的时候 , 我们就可以把它视为是值对象 。 值对象没有状态 , 也不需要有 “标识符” 。 在多数情况下它可以作为一个属性存在于一个实体的内部 。 一般情况下值对象的属性是不可改变的 , 当需要更改属性时 , 可以把整个对象删除 , 然后重新加入一个新对象 。
服务:当实体之间存在某些操作 , 它们并不单一地附属于某一个实体 , 而是跟多个实体都有关联的时候 , 就可以使用服务来封装这些操作 。 值得注意的是服务并非单独指Web Service, 也并非单单存在于领域层 , 而是在各个层当中都会存在服务 , 每一层的服务都有着不同的职能 。 在基础结构层服务可能是用于构建身份验证、电子邮件、错误处理等等操作;在领域层 , 服务更多时候是一种操作 , 它用于协调多个实体之间的关系 , 处理各类的业务问题;在应用层(特别是在分布式开发系统内) , 服务多于Web Service、TCP/IP套接字、MSMQ等等方式实现 , 服务在此处会作为一个与外界通讯的接口;
- 备注 :这里面也存在一定的争议 , Eric 认为实体所代表的只是多个对象之间的关系 , 而它们的动作将会由服务来体现出来 , 这被称为贫血型模型 。 但在开发过程中 , 越来越多人会把动作加入到实体里面 , 这被称为充血型模型 。 其实不同的问题应该客观分析 , 分别对待 , 在这个例子里面将会以按照 Eric 的定义来开发服务 , 在后面的开发过程中大家也可以从中体现一下服务层所带来的好处 。
文章插图2. 实例说明
先以ADO.NET Entity Framework实现模型 , Person、Order分别属于两个实体 , 它们都将继承Root接口 , 在它们的生命周期内都会生成一个Guid作为标志 。 此处把OrderItem作为一个值对象置于Order实体内 , 这意味着OrderItem会通过Order来获取 , 外界不能跨越Order直接获取OrderItem 。 当然这应该由具体的业务情况来确定 , 当外界需要单独调用OrderItem类的时候 , 就应该考虑把OrderItem独立成为一个实体类 。
在这里可利用分部类为实体增加Guid属性 , 关于分部类与分部方法的详细介绍可参考C#综合揭秘——分部类和分部方法
namespace Business.DomainModel{public interface Root {}public partial class Order:Root{private Guid _guid;public Order(){_guid = System.Guid.NewGuid();}//为根对象设置唯一的Guid;public Guid GUID{get { return _guid; }}}public partial class Person:Root{public Person(){_guid = System.Guid.NewGuid();}//为根对象设置唯一的Guid;private Guid _guid;public Guid GUID{get { return _guid; }}}}四、细说Repository1.概念【结合领域驱动设计的SOA分布式软件架构,你还在为这些烦恼?】Repository是把持久化对象转换成领域模型的一种方式 , 可用于获取、更新持久对象并管理它们的生命周期 。 它使应用程序与持久化技术实现解耦 , 程序无需受制于使用Oracle还是MySql数据库 , 也不会受到Hibernate、LINQ、ADO.NET等数据层的约束 , 使开发人员可以把注意力集中到领域模型当中 。
Repository与传统三层模式的DAL层有点相似 , 但Repository针对的是每一个根对象来划分边界的 。 在这个例子当中 , Person与Order都会有对应的PersonRepository、OrderRepository 。 而OrderItem只是Order的子属性 , 所以它的插入、更新、删除都会包含在OrderRepository当中 。 当多个对象之间建立起联系后 , 关系将是复杂的 , 特别是在LINQ里面 , 程序可以轻易通过Person的导航属性里获取OrderItem的值 , 最后很容易使代码变得混乱 。 所以确立Repository的边界 , 可以在有效管理每个Repository的职能 。
2.实例说明
注意OrderItem的存取、删除都包含在OrderRepository里面 。 在获取、修改Order的时候 , 也会利用“显式加载” context.Order.Include("OrderItem") 的方法,使OrderItem实现同步更新 。 而通过PersonRepository.GetPerson(int )获取的Person对象 , 它内部的Order属性将是null值 , 这必须清晰按照领域模型的边界划分的 。
当LINQ面世以后 , 数据的获取变得简单 , 特别在一些小型的系统开发时 , 很多人会不自觉地把这种领域模型的分解规则打破 。 但随着系统的复杂化 , 问题就会逐渐呈现 。 比如当Order对象的属性被更新 , 使用OrderRepository.Update(Order)更新数据库后 , 页面的Person对象未能同步实现更新 , 在Person与数据库交换数据的时候 , Order又被变回旧值 。
在混乱的数据层开发中 , 这种情况非常常见 , 所以在下会坚持Repository的原则 , 把Repository的职能清晰按照领域模型划分 。
- 走向|电商,从货架陈列走向内容驱动
- 率先|还在相片美颜?OPPO已进军视频美妆领域,周冬雨或率先体验
- 制药领域|为什么AI制药这么火,为什么是现在?
- 科技|联咏科技将从明年下半年开始为iPad提供LCD驱动芯片
- 鼓励|(经济)商务部:鼓励引导商务领域减少使用塑料袋等一次性塑料制品
- 博会|第17届东博会:设置5400个实体展位 多领域成果丰硕
- OLED驱动芯片|华为三喜临门,OLED芯片自研成功,鸿蒙OS本月测试
- 驱动|开源之系统:Ubuntu20.04电脑安装无线网卡驱动并解决包依赖关系
- 优选|美团财报电话会议实录:王兴称美团优选是优先战略领域
- 搭档|台湾、东北小伙搭档 打造用工领域“滴滴打车”
