博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一起谈.NET技术,走向ASP.NET架构设计——第五章:业务层模式,原则,实践(后篇)...
阅读量:7184 次
发布时间:2019-06-29

本文共 6106 字,大约阅读时间需要 20 分钟。

  设计模式

  本篇文章主要是接着讨论的在业务层可以采用的或者常用的一些设计模式:

  State模式

  状态模式允许一个对象在随着它的状态变化而改变它自身的一些行为。

  在项目开发的过程中,有一些类,例如一个业务类常常是有自己的一些状态的,而且还存在状态之间的一些转换,有些状态之间是可以进行转换的,有些状态之间是不能转换的。就拿一个汽车来举例子,汽车有很多的状态:静止,启动,前进,后退,停车。而且不能由”前进”状态转为“启动”状态。

  很多朋友知道state模式的用法和结构,朋友们应该也清楚在状态之间的转换用swtich.. case的一些弊端。在项目中,很多时候就没有”一定”,”非得”要用state模式来解决类似的问题,即使可以用state模式来解决。如果变化不大,switch.. case就够用了。

  下面还是来首先来看看使用state模式的一些例子。

  还是采用电子商务为背景来举例:每一个订单都是有状态的:New(新的),Shipped(已经发货),Canceled(已取消)。我们知道一个新的订单可以被变为”取消”的状态,也可以成为”已发货”状态。但是订单不能从”已发货”状态,变为”取消”的状态。

  下面就是例子中的类图:

  首先还是创建一个名为:ASPPatterns.Chap5.StatePattern的解决方案,添加一个名为:ASPPattern.Chap5.StatePattern.Model的类库:

  然后添加在Model的类库中添加一个表示状态接口的定义:IOrderState:

 
public
interface
IOrderState
{
bool
CanShip(Order Order);
void
Ship(Order Order);
bool
CanCancel(Order Order);
void
Cancel(Order order);
OrderStatus Status {
get
; }
}

  下面来定义个表示订单状态的枚举:

 
public
enum
OrderStatus
{
New
=
0
,
Shipped
=
1
,
Canceled
=
2
}

  然后我们来看看,真正要进行状态转化的那个订单类:

 
public
class
Order
{
private
IOrderState _orderState;
public
Order(IOrderState baseState)
{
_orderState
=
baseState;
}
public
int
Id {
get
;
set
; }
public
string
Customer {
get
;
set
; }
public
DateTime OrderedDate {
get
;
set
; }
public
OrderStatus Status()
{
return
_orderState.Status;
}
public
bool
CanCancel()
{
return
_orderState.CanCancel(
this
);
}
public
void
Cancel()
{
if
(CanCancel())
_orderState.Cancel(
this
);
}
public
bool
CanShip()
{
return
_orderState.CanShip(
this
);
}
public
void
Ship()
{
if
(CanShip())
_orderState.Ship(
this
);
}
internal
void
Change(IOrderState OrderState)
{
_orderState
=
OrderState;
}
}

  其实状态模式一个最主要的思想就是:把状态之间的转换分离出来,把每一个状态分解为一个个的状态的类,然后这些状态来负责如何在不同的状态之间的转换。也就是说,就本例而言,以前我们会在Order类中写上如下的语句:

 
public
void
ChangeStatus()
{
switch
(Status)
{
case
OrderStatus.New:
//
.... do some things
break
;
case
OrderStatus.Shipped:
//
.... do some things
break
;
case
OrderStatus.Canceled:
//
.... do some things
break
;
}
}

  我们知道其实此时就是由Order类来控制了状态之间的转换。其实state模式的就是让那些“状态”变为一个“有思想”的状态类,这些类自己来负责如何以及何时转换到其他的状态,这样Order的“负担”就减轻了。还有一个就是大家常常会”批判”:如何要添加一个新的状态,那么ChangeStatus方法势必会变化,因为这个方法控制了状态之间的转换,如果把状态的转换逻辑分离出去,最好做到添加或者减少状态都不会影响现有的Order就更好了。

  下面的讲述有点直接,希望不熟悉state模式的朋友先“撑下去”J

  1、当创建一个订单的时。候,这个订单的状态肯定就是”New”(新的)。那么我们可能就传入一个表示“New”状态的类:OrderNewStatus:

  new Order(OrderNewState newStatus)

  OrderNewStatus把订单的状态标记为New

  我们知道:订单的状态为New的时候,状态可以向Canceled和Shipped转换,那么OrderNewStatus的定义可能如下:

 
public
class
OrderNewState : IOrderState
{
public
bool
CanShip(Order Order)
{
return
true
;
}
public
void
Ship(Order Order)
{
Order.Change(
new
OrderShippedState());
}
public
OrderStatus Status
{
get
{
return
OrderStatus.New; }
}
public
bool
CanCancel(Order Order)
{
return
true
;
}
public
void
Cancel(Order order)
{
order.Change(
new
OrderCanceledState());
}
public
new
Order(OrderNewState newStatus);
}

  2、当新创建的订单处理到一定的流程的时候,例如要发货了,此时要更新订单的状态,此时我们只要调用Order的ship方法就行了。其实此时我们就是在调用NewOrderStatus类的Ship方法,这个类的ship方法知道怎么做:先判断Order的是否可以向Shipped状态转换(调用CanShip方法),如果可以,那么就new一个OrderShippedStatus状态的类,然后用这个类去替换原来的NewOrderStatus(调用Order类的Change方法),这样,Order的状态就是Shipped了,但是Order完全不用管状态之间是如何变化的。

 
public
class
OrderShippedState : IOrderState
{
public
bool
CanShip(Order order)
{
return
false
;
}
public
void
Ship(Order order)
{
throw
new
NotImplementedException(
"
You can't ship a shipped order!
"
);
}
public
OrderStatus Status
{
get
{
return
OrderStatus.Shipped; }
}
public
bool
CanCancel(Order Order)
{
return
false
;
}
public
void
Cancel(Order order)
{
throw
new
NotImplementedException(
"
You can't ship a shipped order!
"
);
}
}

  3、Canceled状态也同理,我这里就不在赘述了。

 
public
class
OrderCanceledState : IOrderState
{
public
bool
CanShip(Order Order)
{
return
false
;
}
public
void
Ship(Order Order)
{
throw
new
NotImplementedException(
"
You can't ship a cancelled order!
"
);
}
public
OrderStatus Status
{
get
{
return
OrderStatus.Canceled; }
}
public
bool
CanCancel(Order Order)
{
return
false
;
}
public
void
Cancel(Order order)
{
throw
new
NotImplementedException(
"
You can't ship a cancelled order!
"
);
}
}

  我们用一个UML图来结束state模式的讲述:

  Strategy模式

  其实策略模式,我这里不打算作太多的讲述,其实这种模式大家到处可见,我们常常在ASP.NET中常常提起的Provider模式,其实就是策略模式的一种实现。

  大家看看结构图,基本上就明白了:

  在上述的图中Context依赖一个IStrategy接口,我们可以决定让Context使用IStrategy的任意的一个实现者:ConcreteStrategyA 或者ConcreteStrategyB。其实就是可以替换不同的实现者。可能大家在数据访问层那块有的体验更加的明显:定义一个IDataProvider,然后实现一个AdoDotNetProvider和一个LinqToSqlProvider。

  架构模式

  下面就来补充一些架构模式的知识,下文主要讲述:Layer Supertype模式(超类模式)

  超类模式就是定义一个基类,然后其他的所有的类都从这个类中继承。对于业务层而言,在超类中可能会定义一些通用的业务规则和验证方法,这样就这些代码被到处分散。也体现了继承的一个好处。

  下面我们就来看一个项目中的例子(电子商务为例),类结构如下:

  大家可以看到,所有的业务类都是从EntityBase继承的。

 
public
abstract
class
EntityBase
<
T
>
{
private
T _Id;
private
bool
_idHasBeenSet
=
false
;
private
IList
<
string
>
_brokenRules
=
new
List
<
string
>
();
public
EntityBase()
{ }
public
EntityBase(T Id)
{
this
.Id
=
Id;
}
public
T Id
{
get
{
return
_Id; }
set
{
if
(_idHasBeenSet)
ThrowExceptionIfOverwritingAnId();
_Id
=
value;
_idHasBeenSet
=
true
;
}
}
private
void
ThrowExceptionIfOverwritingAnId()
{
throw
new
ApplicationException(
"
You cannot change the id of an entity.
"
);
}
public
bool
IsValid()
{
ClearCollectionOfBrokenRules();
CheckForBrokenRules();
return
_brokenRules.Count()
==
0
;
}
protected
abstract
void
CheckForBrokenRules();
private
void
ClearCollectionOfBrokenRules()
{
_brokenRules.Clear();
}
public
IEnumerable
<
string
>
GetBrokenBusinessRules()
{
return
_brokenRules;
}
protected
void
AddBrokenRule(
string
brokenRule)
{
_brokenRules.Add(brokenRule);
}
}

  在这个超类中,提供了保存每个业务类唯一标识的逻辑,并且确保这个标识一旦设定就不会被改变。而且这个超类还提供一些简单的验证逻辑。

  我们再来看看如何使用这个超类,下面定义了一个Customer的业务类:

 
public
class
Customer : EntityBase
<
long
>
{
public
Customer() { }
public
Customer(
long
Id)
:
base
(Id)
{ }
public
string
FirstName {
get
;
set
; }
public
string
LastName {
get
;
set
; }
protected
override
void
CheckForBrokenRules()
{
if
(String.IsNullOrEmpty(FirstName))
base
.AddBrokenRule(
"
You must supply a first name.
"
);
if
(String.IsNullOrEmpty(LastName))
base
.AddBrokenRule(
"
You must supply a last name.
"
);
}
}

  在这个类中,我们定义了唯一标识的类型:long,而且还定义了一些业务规则:FirstName, LastName不为空。至于如何调用这些验证规则,在超类中已经实现了,此时业务类就“轻松”了很多—起码不用再次写那些相类似的代码了,实现了一定程度上的代码重用。

  今天就讲到这里了,不正确之处,还望朋友们指出,见谅!

  多谢支持!

   

转载地址:http://meukm.baihongyu.com/

你可能感兴趣的文章
富文本编辑器焦点
查看>>
机器学习认知
查看>>
iOS应用程序生命周期(前后台切换,应用的各种状态)详解
查看>>
$GLOBALS ["HTTP_RAW_POST_DATA"]为空
查看>>
谷歌浏览器中,js首次打印,图片没显示
查看>>
设计自己解析XML字段,并反射到对应类
查看>>
linux 下安装maven + git直接编译项目
查看>>
oracle用sum函数实现累加
查看>>
java中创建对象的方法
查看>>
UNIX/Linux系统取证之信息采集案例
查看>>
Python知识点总结篇(五)
查看>>
一致性算法探寻(扩展版)1
查看>>
这几个 Chrome 的 Tab 增强插件你都用上了吗?
查看>>
Java中的浅拷贝与深拷贝
查看>>
微信小程序联盟:官方文档+精品教程+demo集合(6月9日更新,持续更新中……)...
查看>>
spring 事务的传播特性
查看>>
react学习(1)-Why React?
查看>>
RESTful风格的API接口开发教程
查看>>
用 Lua 实现一个微型虚拟机-基本篇
查看>>
php 安装 memcached 扩展出现 zlib 错误
查看>>