面向领域开发

面向领域开发示例

    最近面向领域的知识挺火,我也来插一腿。说说我平时做项目时候用到的开发方式,以下代码为伪代码,主要展示一下我现在的开发方式供大家讨论,系统中不考虑持久、UIAOPIOC等方面内容。

    说到.NET社区的“开发方式”就不得不提一下Petshop了,可以说Petshop真是影响了.NET的一代人。以至于三层成了.NET这边流行的标准的开发方式。但是要说一下Petshop是数据库驱动业务核心的过程式开发,也正是它也毒害了一批人。

 

下面我们以一个最常见也是大家比较熟的下定单来简单看一下。首先是系统的几个领域类:

 面向领域开发_第1张图片 

应牧章的要求,加上类之间的关系:这里的关系很简单,Order与OrderItem是一对多关系;OrderItem与Product是一对多关系;定单提交业务Order对象是个“根”

我也就不解释了,发下几个类的代码里面有注解。大家看一下就明白了。这里我们要强调的是类关系,还有一个根的概念。每个业务流都会有一个根。而根不是整个系统唯一确定的是而是根据对象在哪个业务范围内而决定的。显然这里面是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
    }

 

 

接下来看看我这个伪代码的项目结构。做的很简单,简单明快的架构就是好的架构,不要把架构搞的很复杂。

 

面向领域开发_第2张图片 

Domain:领域层,里面放的是领域对象。这个层对其它层没有依赖

Repository:持久层,对领域对象进行持久。里面可以有级存和DB等。这个层依赖Domain

Services:应用程序服务,这个名字喜好着起吧。我们可以把它理解为业务逻辑层,当然这个业务逻辑是对一个功能更粗粒度的API。里面会调用依赖的领域对象进行业务组合达到业务需求。当然对对象的持久也是这里来做的。这个层依赖DomainRepository

 

WebUI层,调用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里面的是伪代码,就不发了。

 

工作呢,写的很粗略。最后说一点,其实面向领域开发通过这些代码是看不出本质的。我在这总结一下。

 

把你的开发关注点提到类(对象)上来,不要把关注点放到数据库(表)上。

你可能感兴趣的:(开发)