走向.NET架构设计—第四章—业务层分层架构(中篇)
前言: 在上一篇文章中,我们讨论了两种组织业务逻辑的模式:Transaction Script和Active Record。在本篇中开始讲述Domain Model和Anemic Model。
注:不管技术的道路多么难走,我们还是得踏踏实实的把技术做下去。也希望朋友们能够一如既往的支持本系列。
本篇议题如下:Transaction Scrip(前篇)Active Record前篇)Domain Model(中篇)Anemic Model(后篇)DDD(后篇)
Domain Model:
在开发过程中,我们常常用Domain Model来对目标的业务领域建模。通过Domain Model建模的业务类代表了目标领域中的一些概念。而且,我们会看到通过Domain Model建模的一些对象模拟了业务活动中的数据,有的对象还反映了一些业务规则。
我们就来看看电子商务系统的开发,在开发中我们建立了一些概念的模型来反映电子商务领域中的一些概念:购物车,订单,订单项等。这些模型有自己的数据,行为。例如一个订单模型,它不仅仅包含一些属性(流水号,创建日期,状态)来包含自己的数据,同时它也包含了一些业务逻辑:下订单的用户时候合法,下订单用户的余额是否充足等。
一般来说,我们对领域了解的越深,我们在软件中建立的模式越接近现实中的概念,最后实现的软件就越符合客户的需求。同时在建模的过程中,也要考虑模型的可实现行,可能我们对领域进行了很好的建模,和符合目标领域的一些概念,但是在软件实现起来非常的困难,那么就得权衡一下:找出一个比较好的模式,同时也便于实现。
在以前的文章中其实也提到过一些有关Domain Model的一些东西,其实Domain Model和Active Record的一个区别在于:Domain Model不知道自己的数据时如何持久化的,即PI(Persistence Ignorance).也就是说,通过Domain Model建立的业务类,都是POCO(Plain Old Common Runtime Object)。
创建一个新的解决方案,命名为ASPPatterns.Chap4.DomainModel,并且添加如下的项目:
下面就来看看每个项目代表的含义:
其中:
q AgileSharp.Chapter4.DomainModel.Model:业务层,在这个类库项目中包含了系统中所有的业务逻辑和业务对象,以及业务对象之间的关系。这个项目也定义了持久化领域对象的接口,并且是用Repository 模式来实现的(Repository 这个模式我们后面会谈到)。这个Model层没有对其他的类库项目进行引用,完全关注于业务。
q AgileSharp.Chapter4.DomainModel.Repository:这个Repository的类库项目实现了在Model 类库中定义的持久化接口。Repository对Model 类库项目进行了引用。
q AgileSharp.Chapter4.DomainModel.Infrastructure:提供辅助功能,例如发送邮件,记录日志等。
q AgileSharp.Chapter4.DomainModel.Contact:包含数据契约和服务契约。
q AgileSharp.Chapter4.DomainModel.Service:服务层,实现契约层提供的服务接口,并且通过Web Service接口向外界暴露服务。
q AgileSharp.Chapter4.DomainModel.WCFHost:WCF宿主程序。
q AgileSharp.Chapter4.DomainModel.WPFUI:主要是负责最后的显示逻辑和一些用户体验的实现。这个类库调用服务层提供的API,来提交请求和显示结果。
很多时候可以根据业务模型设计出数据模型(例如,数据表),然后采用相应的策略,并遵循一定的规则,来确保对数据进行高效存取(有关数据模型和领域模型的相关话题,在本书第7章的“领域模型 VS. 逻辑模型”一节会详细讲述)。此处,领域模型比较简单,对应的数据模型的结构基本和领域模型一样,但是在很多的系统中,领域模型和数据模型是不一样的,例如,一个业务模型的数据要来自于多个数据模型。
下面首先建立Order领域类,如下所示:
public class Order
{
public string OrderNo { get; set; }
public OrderStatus Status { get; set; }
public List<OrderItem> Items { get; set; }
//计算订单的总价
public decimal CaculateTotalPrice()
{
decimal result = 0;
if (this.Items != null && this.Items.Count > 0)
{
result = this.Items.Sum(u => u.Products.Sum(p => p.Price));
}
return result;
}
//检查订单的状态,判断订单是否已经被处理
public bool CheckStatus()
{
return this.Status != OrderStatus.Processed;
}
}
public enum OrderStatus
{
New,
Processed
}
}
{
public string OrderNo { get; set; }
public OrderStatus Status { get; set; }
public List<OrderItem> Items { get; set; }
//计算订单的总价
public decimal CaculateTotalPrice()
{
decimal result = 0;
if (this.Items != null && this.Items.Count > 0)
{
result = this.Items.Sum(u => u.Products.Sum(p => p.Price));
}
return result;
}
//检查订单的状态,判断订单是否已经被处理
public bool CheckStatus()
{
return this.Status != OrderStatus.Processed;
}
}
public enum OrderStatus
{
New,
Processed
}
}
正如之前所讲:每个业务类只关注自身的业务,而每个流程又是多个业务类和其他一些辅助类组合完成的,很多的时候都会在领域层中加入服务类,形成很“薄”的服务层(也称为应用层)。下面我们来讨论一下有关服务层的话题(本书的第5章将对服务层进行深入讨论)。
处理领域逻辑常见的方法是将领域层(也称“业务层”)细分为两层:在领域层中把服务类独立出来,作为服务层
数据访问在这里的实现比较简单,主要是用Linq To Sql来实现IOrderRepository 和IProductRepository接口的,代码如下所示,此处不再赘述:
public interface IOrderRepository
{
bool Save(Order order);
}
public interface IProductRepository
{
Product GetProductByName(string productName);
}
{
bool Save(Order order);
}
public interface IProductRepository
{
Product GetProductByName(string productName);
}
最后我们就是处理显示层。
在本例子中,显示层就是用传统的ASP.NET来实现的,而且用了最简单的实现,如果需要,大家可以采用MVP模式,这点在我的另一文章(走向.NET架构设计—第三章—分层设计,初涉架构(中篇) )中详细的讲述了,这里不在赘述,也希望大家见谅。
到这里Domain Model就基本讲述完了,我们可以看出:当软件中的业务比较的负责的时候,我们用Domain Model可能比较的好。因为用Domain Model的时候,我们的把所有的精力主要关注在对业务领域的建模,把业务的概念抽象出来,变为软件可以实现的模型。其实抽象出业务模式不是那么容易的事情,往往必须对领域作出比较深入的分析才行。
同时,在业务建模和可实现性之间要有权衡,有时候,我们把业务分析的很透,但是分析出来的概念无法转为实现,产生了“水至清则无鱼”。希望大家多多的琢磨几种组织业务逻辑模式的区别。
今天就到这里了,还是希望多多见谅,支持!谢谢啊!
本文转自yanyangtian51CTO博客,原文链接:http://blog.51cto.com/yanyangtian/415734 ,如需转载请自行联系原作者