面向领域开发示例【转】
最近面向领域的知识挺火,我也来插一腿。说说我平时做项目时候用到的开发方式,以下代码为伪代码,主要展示一下我现在的开发方式供大家讨论,系统中不考虑持久、 UI 、 AOP 和 IOC 等方面内容。
说到 .NET 社区的“开发方式”就不得不提一下 Petshop 了,可以说 Petshop 真是影响了 .NET 的一代人。以至于三层成了 .NET 这边流行的标准的开发方式。但是要说一下 Petshop 是数据库驱动业务核心的过程式开发,也正是它也毒害了一批人。
下面我们以一个最常见也是大家比较熟的下定单来简单看一下。首先是系统的几个领域类:
我也就不解释了,发下几个类的代码里面有注解。大家看一下就明白了。这里我们要强调的是类关系,还有一个根的概念。每个业务流都会有一个根。而根不是整个系统唯一确定的是而是根据对象在哪个业务范围内而决定的。显然这里面是 Order 定单对象。
/// <summary>
/// 商品
/// </summary>
public class Product
{
/// <summary>
/// 键
/// </summary>
public int SysNo { get ; set ; }
/// <summary>
/// 商品名称
/// </summary>
public string ProductName { get ; set ; }
/// <summary>
/// 商品价格
/// </summary>
public decimal ProductPrice { get ; set ; }
private Category _category;
/// <summary>
/// 所属分类
/// </summary>
public Category Category
{
get { return _category; }
set { _category = value; }
}
}
/// <summary>
/// 定单
/// </summary>
public class Order
{
#region 属性
/// <summary>
/// 键
/// </summary>
public int SysNo { get ; set ; }
/// <summary>
/// 定单ID
/// </summary>
public string OrderId { get ; set ; }
/// <summary>
/// 定单金额
/// </summary>
public decimal OrderAmount { get ; set ; }
/// <summary>
/// 运费金额
/// </summary>
public decimal ShipAmount { get ; set ; }
/// <summary>
/// 支付金额
/// </summary>
public decimal PayAmount { get ; set ; }
/// <summary>
/// 定单状态
/// </summary>
public int OrderStatus { get ; set ; }
/// <summary>
/// 定单时间
/// </summary>
public DateTime OrderTime { get ; set ; }
private List < OrderItem > _orderItems = new List < OrderItem > ();
/// <summary>
/// 定单明细
/// </summary>
public List < OrderItem > OrderItems
{
get { return _orderItems; }
set { _orderItems = value; }
}
#endregion
#region 方法
/// <summary>
/// 计算定单金额
/// </summary>
/// <returns></returns>
public decimal GetOrderAmount()
{
decimal amount = 0 ;
// 计算商品金额
foreach (var item in OrderItems)
{
amount += item.GetAmount();
}
// 加上运费
amount += ShipAmount;
return amount;
}
#endregion
}
/// <summary>
/// 定单明细
/// </summary>
public class OrderItem
{
#region 属性
/// <summary>
/// 键
/// </summary>
public int SysNo { get ; set ; }
private Product _product = new Product();
/// <summary>
/// 购买商品
/// </summary>
public Product Product
{
get { return _product; }
set { _product = value; }
}
/// <summary>
/// 购买价格
/// </summary>
public decimal ProductPrice { get ; set ; }
/// <summary>
/// 购买数量
/// </summary>
public int ProductQty { get ; set ; }
#endregion
#region 方法
/// <summary>
/// 主算小计金额
/// </summary>
/// <returns></returns>
public decimal GetAmount()
{
return this .ProductPrice * Convert.ToDecimal( this .ProductQty);
}
#endregion
}
/// <summary>
/// 商品库存
/// </summary>
public class Inventory
{
#region 属性
/// <summary>
/// 键
/// </summary>
public int SysNo { get ; set ; }
/// <summary>
/// 更新键,用来保证更新的数据之前没有别人更新过。对应表的ModKey列,每更新一次更新Guid值
/// </summary>
public Guid ModKey { get ; set ; }
private Product _product = new Product();
/// <summary>
/// 商品
/// </summary>
public Product Product
{
get { return _product; }
set { _product = value; }
}
/// <summary>
/// 库存数量
/// </summary>
public int Qty { get ; set ; }
#endregion
#region 方法
/// <summary>
/// 验证库存是否有库存
/// </summary>
/// <returns></returns>
public bool ValidInventory()
{
if ( this .Qty > 0 )
return true ;
else
return false ;
}
/// <summary>
/// 减库存
/// </summary>
/// <param name="qty"></param>
public void MinusInventory( int qty)
{
if ( this .Qty < qty)
throw new Exception( " 库存不足! " );
this .Qty -= qty;
}
#endregion
}
接下来看看我这个伪代码的项目结构。做的很简单,简单明快的架构就是好的架构,不要把架构搞的很复杂。
Domain :领域层,里面放的是领域对象。这个层对其它层没有依赖
Repository :持久层,对领域对象进行持久。里面可以有级存和 DB 等。这个层依赖 Domain
Services :应用程序服务,这个名字喜好着起吧。我们可以把它理解为业务逻辑层,当然这个业务逻辑是对一个功能更粗粒度的 API 。里面会调用依赖的领域对象进行业务组合达到业务需求。当然对对象的持久也是这里来做的。这个层依赖 Domain 和 Repository
Web : UI 层,调用 Services 进行业务处理,需要 ViewModel(VO) 我们可以加,我个人比较喜欢按需要创建 ViewModel 对象,不需要的没必要增加工作量。
基本流程就是
UI 调用 Serivices 创建定单
Services 调用 Domain 对象进行业务组合处理
最后 Services 调用 Repository 进行对象的持久
我们从上到下,首先是UI的控制器里面开始。生成定单
public ActionResult About()
{
// 创建定单,生成定单必要数据收货信息,购物车信息等
Order order = new Order();
OrderService service = new OrderService();
service.OrderBuy(order); // 定单提交
return View();
}
然后是Services里面的方法
/// <summary>
/// 定单提交
/// </summary>
/// <param name="order"></param>
public void OrderBuy(Order order)
{
// 事务开始
order.OrderAmount = order.GetOrderAmount(); // 计算订单金额
// 更新库存
foreach (var item in order.OrderItems)
{
Inventory inventory = InventoryRepository.LoadInventory(item.Product); // 取得一个库存对象
inventory.MinusInventory(item.ProductQty); // 调用库存调用方法
InventoryRepository.SaveInventory(inventory); // 持久更新完的库存
}
OrderRepository.SaveOrder(order); // 持久化定单
// 事务结束
}
Repository里面的是伪代码,就不发了。
工作呢,写的很粗略。最后说一点,其实面向领域开发通过这些代码是看不出本质的。我在这总结一下。
把你的开发关注点提到类(对象)上来,不要把关注点放到数据库(表)上。
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息