您的位置:首页 > 编程语言

DDD:订单管理 之 如何组织代码

2013-07-03 09:26 239 查看

背景

系统开发最难的是职责的合理分配,或者叫:“如何合理的组织代码”,今天说一个关于这方面问题的示例,希望大家多批评。

示例背景

参考数据字典



需求

OrderCode必须唯一。

Total = Sum(Subtotal)。

订单有三种状态:【未提交】、【待审核】和【已审核】,合理的状态迁移有:【未提交】----》【待审核】和【待审核】----》【已审核】,只有处于【未提交】状态的订单能修改。

订单和订单项中的状态必须合法,规则自己定义。

示例实现

项目结构



Application:应用层,负责领域逻辑的封装。主要角色:ApplicationService、CommandHandler。

Boostrap:启动管理层,负责启动过程管理,如:注册Ioc、初始化配置。主要角色:BootstrapListener。

Commands:命令层,是一个契约层。主要角色:Comamnd、DTO。

Controllers:控制器层,边界层。主要角色:Controller。

Domain:领域层,负责领域逻辑的组织。主要角色:Aggregate、Entity、ValueObject、Factory、DomainService、IRepository、IUnitOfWork。

Events:事件层,是一个契约层,跨聚合流程可以采用。主要角色:Event。

EventSubscribers:事件监听层。主要角色:EventSubscriber。

Infrastructure:基础设施层。主要角色:Repository、QueryService、UnitOfWork。

Query:查询层,为UI的查询提供服务,主要角色:QueryService。

项目整体采用简单的CQRS架构,Command端采用DDD组织,Query直接从数据库返回dynamic类型。Event可以用来处理跨聚合通信,也可以用来处理长事务或离线事务。

重点介绍的领域层



采用状态模式处理状态迁移。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Happy.Example.Domain.TestOrders
{
public interface ITestOrderState
{
void AddTestOrderDetail(TestOrderDetail testOrderDetail);

void UpdateTestOrderDetail(Guid testOrderDetailId, decimal subtotal);

void RemoveTestOrderDetail(Guid testOrderDetailId);

void Commit();

void Verify();

string Status { get; }

TestOrder TestOrder { set; }
}
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Happy.Example.Domain.TestOrders
{
public partial class TestOrder
{
private abstract class TestOrderState : ITestOrderState
{
public virtual void AddTestOrderDetail(TestOrderDetail testOrderDetail)
{
this.ThrowInvalidOperationException();
}

public virtual void UpdateTestOrderDetail(Guid testOrderDetailId, decimal subtotal)
{
this.ThrowInvalidOperationException();
}

public virtual void RemoveTestOrderDetail(Guid testOrderDetailId)
{
this.ThrowInvalidOperationException();
}

public virtual void Commit()
{
this.ThrowInvalidOperationException();
}

public virtual void Verify()
{
this.ThrowInvalidOperationException();
}

public abstract string Status { get; }

public TestOrder TestOrder { protected get; set; }

private void ThrowInvalidOperationException()
{
throw new InvalidOperationException(string.Format("处于【{0}】的订单不能执行此操作!", this.Status));
}
}
}
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Happy.Example.Domain.TestOrders
{
public partial class TestOrder
{
private sealed class UnCommitted : TestOrderState
{
internal static readonly string UnCommittedStatus = "未提交";

public override void AddTestOrderDetail(TestOrderDetail testOrderDetail)
{
this.TestOrder.DoAddTestOrderDetail(testOrderDetail);
}

public override void UpdateTestOrderDetail(Guid testOrderDetailId, decimal subtotal)
{
this.TestOrder.DoUpdateTestOrderDetail(testOrderDetailId, subtotal);
}

public override void RemoveTestOrderDetail(Guid testOrderDetailId)
{
this.TestOrder.DoRemoveTestOrderDetail(testOrderDetailId);
}

public override void Commit()
{
this.TestOrder.DoCommit();
}

public override string Status
{
get { return UnCommittedStatus; }
}
}
}
}


采用封装集合手法处理Total的同步问题。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Happy.Domain;
using Happy.Domain.Tree;
using Happy.Infrastructure.ExtentionMethods;
using Happy.Example.Events.TestOrders;

namespace Happy.Example.Domain.TestOrders
{
public partial class TestOrder : AggregateRoot<Guid>
{
private ITestOrderState _orderState;

protected TestOrder() { }

public TestOrder(string orderCode, string customer)
{
orderCode.MustNotNullAndNotWhiteSpace("orderCode");
customer.MustNotNullAndNotWhiteSpace("customer");

this.Id = Guid.NewGuid();
this.OrderCode = orderCode;
this.Customer = customer;
this.OrderState = TestOrderStateFactory.CreateUnCommittedTestOrderState(this);
this.TestOrderDetails = new List<TestOrderDetail>();
}

public virtual System.String OrderCode { get; protected set; }
public virtual System.String Customer { get; protected set; }
public virtual System.Decimal Total { get; protected set; }
public virtual System.String Status { get; protected set; }
public virtual ICollection<TestOrderDetail> TestOrderDetails { get; protected set; }

private ITestOrderState OrderState
{
get
{
if (_orderState == null)
{
_orderState = TestOrderStateFactory.Create(this, this.Status);
}

return _orderState;
}
set
{
_orderState = value;
this.Status = value.Status;
}
}

public void AddTestOrderDetail(TestOrderDetail testOrderDetail)
{
this.OrderState.AddTestOrderDetail(testOrderDetail);
}

public void UpdateTestOrderDetail(Guid testOrderDetailId, decimal subtotal)
{
this.OrderState.UpdateTestOrderDetail(testOrderDetailId, subtotal);
}

public void RemoveTestOrderDetail(Guid testOrderDetailId)
{
this.OrderState.RemoveTestOrderDetail(testOrderDetailId);
}

public void Commit()
{
this.OrderState.Commit();
}

public void Verify()
{
this.OrderState.Verify();
}

private void DoAddTestOrderDetail(TestOrderDetail testOrderDetail)
{
this.TestOrderDetails.Add(testOrderDetail);

this.Total += testOrderDetail.Subtotal;
}

private void DoUpdateTestOrderDetail(Guid testOrderDetailId, decimal subtotal)
{
var testOrderDetail = this.TestOrderDetails.First(x => x.Id == testOrderDetailId);

this.Total -= testOrderDetail.Subtotal;
testOrderDetail.Subtotal = subtotal;
this.Total += testOrderDetail.Subtotal;
}

private void DoRemoveTestOrderDetail(Guid testOrderDetailId)
{
var testOrderDetail = this.TestOrderDetails.First(x => x.Id == testOrderDetailId);

this.TestOrderDetails.Remove(testOrderDetail);
this.Total -= testOrderDetail.Subtotal;
}

private void DoCommit()
{
this.OrderState = TestOrderStateFactory.CreatePendingVerificationTestOrderState(this);
}

private void DoVerify()
{
this.OrderState = TestOrderStateFactory.CreateVerifiedTestOrderState(this);

this.PublishEvent(new TestOrderVerified());
}
}
}


效果图



背景

写这个简单的Demo过程,遇到了很多小的决策,这篇文章就看做一个开头吧,后边重点介绍每个决策点,在一篇文章中真的很难说完,喜欢看代码的朋友,先去https://happy.codeplex.com/下载。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: