提供3000多款全球软件/控件产品
针对软件研发的各个阶段提供专业培训与技术咨询
根据客户需求提供定制化的软件开发服务
全球知名设计软件,显著提升设计质量
打造以经营为中心,实现生产过程透明化管理
帮助企业合理产能分配,提高资源利用率
快速打造数字化生产线,实现全流程追溯
生产过程精准追溯,满足企业合规要求
以六西格玛为理论基础,实现产品质量全数字化管理
通过大屏电子看板,实现车间透明化管理
对设备进行全生命周期管理,提高设备综合利用率
实现设备数据的实时采集与监控
利用数字化技术提升油气勘探的效率和成功率
钻井计划优化、实时监控和风险评估
提供业务洞察与决策支持实现数据驱动决策
转帖|其它|编辑:郝浩|2010-11-15 14:25:46.000|阅读 524 次
概述: 在上一章中,我们讲述了有关业务层分层的一些知识,下面我们就来看看,在具体的业务层的设计中,我们可以采用哪些模式可以将业务层设计的更加的灵活!
# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>
不管是GOF的23种设计模式,还是Flower的企业架构模式,相信很多的朋友知道或者听说过。在那些很经典的书中,对模式都做了很精辟的解释,本篇的目的在于看看这些模式如何应用在项目中的,并且给出一些代码的例子,小洋也希望大家能够真正的理解这些模式的思想,而不仅仅停留在代码结构和表面上。
在上一章中,我们讲述了有关业务层分层的一些知识,下面我们就来看看,在具体的业务层的设计中,我们可以采用哪些模式可以将业务层设计的更加的灵活!
架构模式
首先我们就来看看,如何更加有效的组织业务规则。
Specification Pattern(需求规格模式)
这个模式的使用方法就是:把业务规则放在业务类的外面,并且封装成为一个个返回boolean值的算法。这些一个个的业务规则的算法不仅仅便于管理和维护,并且还可以被重用,而且很方便的组织成为复杂的业务逻辑。
下面我们就来看一个以在线租DVD的公司的例子。例子很简单,场景也很简单:判断一个用户是否可以租更多的DVD。下面就是我们设计的一个基本的类图。(大家肯定觉得一上来就看类图有点突兀,没有一步步的分析,其实我是想让大家知道,所讲的是个什么东西样子,之后大家再慢慢的理解)
下面我们就开始做这个事情:
1. 创建一个新的解决方案,命名为:ASPPatterns.Chap5.Specification,
2. 然后添加一个C#的类库:ASPPatterns.Chap5. Specification.Model。
3. 在这个Model的类库中添加一个接口:ISpecification
cation.Solution.PNG" width="1005" border="0">
public interface ISpecification<T>
{
bool IsSatisfiedBy(T candidate);
}
上面的代码,其实就是把一个个的业务规则抽象出来了。我们知道,在系统中,不管业务规则多么复杂,最后在进行业务逻辑判定的时候,最后的结果还是“是否通过”。所以在这里就进行了抽象。
因为我们的例子是以一个在线租赁DVD为例子,用户可以来租赁DVD,其中也是有一定的规则的,例如,如果用户已经租了5盘DVD,那么我们就会考虑,这个用户时候还可以继续租DVD。至于根据什么判断:可能DVD公司规定一个人最多不能超过5盘,或者DVD公司认为某个用户的信誉不好等等。
下面我们就来定义个具体的业务规则:HasReachedRentalThresholdSpecification
根据这个规则就决定一个用户是否可以租DVD。
public class HasReachedRentalThresholdSpecification :
ISpecification<CustomerAccount>
{
public override bool IsSatisfiedBy(CustomerAccount candidate)
{
return candidate.NumberOfRentalsThisMonth >= 5;
}
}
这个规则定义出来后,我们就在业务类中使用这个规则:
public class CustomerAccount
{
private ISpecification<CustomerAccount> _hasReachedRentalThreshold;
public CustomerAccount()
{
_hasReachedRentalThreshold =
new HasReachedRentalThresholdSpecification();
}
public decimal NumberOfRentalsThisMonth { get; set; }
public bool CanRent()
{
return !_hasReachedRentalThreshold.IsSatisfiedBy(this);
}
}
当然,我们可以把更多的业务规则组合进来。
这个例子到这里就完了,这个例子中只是简单的采用了Specifiction模式。但是实际的情况往往是没有这个简单的,因为一个业务逻辑往往要组合多个多个业务规则。下面我们就来进一步的看:如果采用链式的结构来完成复杂的业务逻辑。
Composite Pattern(组合模式)
注:这个模式不属于架构模式,而且GOF模式的一种,这里列出来主要是为了配合之前的Specification模式的,大家不要在这里纠结这个问题 J
Composite模式允许把一个集合对象当做单个的对象来使用,而且我们还可以在这个所谓的”单个对象”中不断的嵌套。采用这种模式,可以把对象的层级关系组合成为“树形”的结构!我个人喜欢把它称为“容器模式”。
其实这个模式在我们在平时的ASP.NET或者WinForm ,WPF中到处可见。例如一个Panel控件,可以在里面加入另一个Panel,然后在Panel中可以加入GroupBox,然后再GroupBox中还可以加入Button等控件。这就是.NET Framework设计中采用了Compiste模式的例子。
下面来看看Compiste模式的UML结构图:
在上面的图中:
1. Component是一个抽象类,这个类提供了一个Add方法,这个Add可以加入其他的Component.大家想想,这样是否就可以很容易的实现链式的效果。
2. Leaf就是一个继承Component的具体类。
看到上面图,其实大家也可以想想在ASP.NET页面的生命周期中到处都是这种例子:例如在ASP.NET页面的Init事件中,因为Page本身就是一个容器,这个容器里面包含了很多的其他的控件,如Panel,Button,而且Panel里面还是控件。那么在Init方法就会调用自己的子容器的Init方法,然后子容器在调用自己的子容器的Init方法,这样就层层调用,直到最后调用到某个控件的Init的方法。这样这个页面的初始化就完成了。和上面的UML的结构是一样的。
下面我们还是来看一个例子吧。继续之前的Specification模式的讨论,看看如果结合则两种模式来组织复杂的业务逻辑。
为了使得例子有点说服力,我们把之前的业务稍微的变复杂一点点:为了判定一个用户是否可以租DVD,我们要进行一系列的规则判定之后才能决定结果:
1. 用户的账号是否处于激活的状态
2. 用户之前是否还欠费
3. 用户租赁DVD的数量是否达到了规定的数量
下面首先总体来看看一些类图的结构:
不知道大家有没有注意一点:每次我在讲述一个功能的时候,总是先让大家看看总体的类图的设计,然后再开始一个个的讲述。其实这样做事有原因的。在之前的文章中,一直提到“设计Design”。就是说在做一个功能之前,不是一下子就砸进去编码,而是首先把功能考虑清楚,然后从总体上考虑功能如何实现,然后写出一些测试代码,最后写出一些实现代码的骨架。上面的类图其实就是一个骨架。
骨架出来了,下面就继续开始实现,首先,因为要考虑到用户有了”是否处于激活状态”,那么就在之前的CustomerAccoutn中加入属性AccountActive.而且还要加入另外的属性LateFees来保存用户的欠费的多少。
public class CustomerAccount
{
private ISpecification<CustomerAccount> _
hasReachedRentalThreshold;
public CustomerAccount()
{
_hasReachedRentalThreshold =
new HasReachedRentalThresholdSpecification(); }
public decimal NumberOfRentalsThisMonth { get; set; }
public bool AccountActive { get; set; }
public decimal LateFees { get; set; }
public bool CanRent()
{
return !_hasReachedRentalThreshold.IsSatisfiedBy(this);
}
}
那么随着这个需求的变化,之前的CanRent方法也要改变了。
按照之前的Specification模式的例子,我们首先条件两个类来新增的封装业务规则:
public class CustomerAccountStillActiveSpecification :
ISpecification<CustomerAccount>
{
public override bool IsSatisfiedBy(CustomerAccount candidate)
{
return candidate.AccountActive;
}
}
上面的代码用来判断用户是否处于激活状态
public class CustomerAccountHasLateFeesSpecification :
ISpecification<CustomerAccount>
{
public override bool IsSatisfiedBy(CustomerAccount candidate)
{
return candidate.LateFees > 0;
}
}
上面的代码就判断用户是否欠费
添加完了所有的业务规则之后,好戏就开始了。
我们要把这些业务规则组合起来,放在容器中,然后只要调用父容器的一个方法,规则验证就一层层进行下去,就像我们之前举的ASP.NET的Init事件一样。
首先我们来添加一个表示容器的类:
public abstract class CompositeSpecification<T> : ISpecification<T>
{
public abstract bool IsSatisfiedBy(T candidate);
public ISpecification<T> And(ISpecification<T> other)
{
return new AndSpecification<T>(this, other);
}
public ISpecification<T> Not()
{
return new NotSpecification<T>(this);
}
}
上面的代码有些不明白的地方,没什么,咱们耐心的往下面走。
public class AndSpecification<T> : CompositeSpecification<T>
{
private ISpecification<T> _leftSpecification;
private ISpecification<T> _rightSpecification;
public AndSpecification(ISpecification<T> leftSpecification,
ISpecification<T> rightSpecification)
{
_leftSpecification = leftSpecification;
_rightSpecification = rightSpecification;
}
public override bool IsSatisfiedBy(T candidate)
{
return _leftSpecification.IsSatisfiedBy(candidate)
&& _rightSpecification.IsSatisfiedBy(candidate);
}
}
public class NotSpecification<T> : CompositeSpecification<T>
{
private ISpecification<T> _innerSpecification;
public NotSpecification(ISpecification<T> innerSpecification)
{
_innerSpecification = innerSpecification;
}
public override bool IsSatisfiedBy(T candidate)
{
return !_innerSpecification.IsSatisfiedBy(candidate);
}
}
上面基础代码完成了,我们就开始实现我们想要的链式的效果!
我们修改之前的几个规则,和接口的定义,如下:
public class HasReachedRentalThresholdSpecification :
CompositeSpecification<CustomerAccount>
{
…
}
public class CustomerAccountStillActiveSpecification :
CompositeSpecification<CustomerAccount>
{
…
}
public class CustomerAccountHasLateFeesSpecification :
CompositeSpecification<CustomerAccount>
{
…
}
漫长的过程终于结束了,到了核心的部分,请看业务类现在的定义:
public class CustomerAccount
{
private ISpecification<CustomerAccount> _hasReachedRentalThreshold;
private ISpecification<CustomerAccount> _customerAccountIsActive;
private ISpecification<CustomerAccount> _customerAccountHasLateFees;
public CustomerAccount()
{
_hasReachedRentalThreshold =
new HasReachedRentalThresholdSpecification();
_customerAccountIsActive =
new CustomerAccountStillActiveSpecification();
_customerAccountHasLateFees =
new CustomerAccountHasLateFeesSpecification();
}
public decimal NumberOfRentalsThisMonth { get; set; }
public bool AccountActive { get; set; }
public decimal LateFees { get; set; }
public bool CanRent()
{
ISpecification<CustomerAccount> canRent =
_customerAccountIsActive.And(_hasReachedRentalThreshold.Not()).And(_customerAccountHasLateFees.Not());
return canRent.IsSatisfiedBy(this);
}
}
大家主要看看那个 CanRent方法
下面我们就来讲讲这个方法。
customerAccountActive继承自CompositeSpecification,而Add方法的定义如下:
public ISpecification<T> And(ISpecification<T> other)
{
return new AndSpecification<T>(this, other);
}
_customerAccountIsActive.And(_hasReachedRentalThreshold.Not())的结果就是使得customerAccountIsActive内部包含了平行的两条业务规则,结构如下:
方法返回的结果还是一个实现了ISpecification的对象,只不过这个对象(我们称之为“容器A”)里面有两个规则了。
然后这个保量两个业务规则的对象(容器A)再次调用Add方法,如下:
_customerAccountIsActive.And(_hasReachedRentalThreshold.Not()).
And(_customerAccountHasLateFees.Not());
此时相当于把之前那个容器A作为一个单独对象,再次调用Add方法,于是这个三个规则组合成为一个大的规则的容器:如下。
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn
文章转载自:博客园面对“数字中国”建设和中国制造2025战略实施的机遇期,中车信息公司紧跟时代的步伐,以“集约化、专业化、标准化、精益化、一体化、平台化”为工作目标,大力推进信息服务、工业软件等核心产品及业务的发展。在慧都3D解决方案的实施下,清软英泰建成了多模型来源的综合轻量化显示平台、实现文件不失真的百倍压缩比、针对模型中的大模型文件,在展示平台上进行流畅展示,提升工作效率,优化了使用体验。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
服务电话
重庆/ 023-68661681
华东/ 13452821722
华南/ 18100878085
华北/ 17347785263
客户支持
技术支持咨询服务
服务热线:400-700-1020
邮箱:sales@pclwef.cn
关注我们
地址 : 重庆市九龙坡区火炬大道69号6幢