走向.NET
架构设计—
第五章—
业务层模式,原则,实践(后篇)
前言:在上一篇文章中,讲述了一些设计模式的使用,本篇首先接着介绍还没有讲完的一些设计模式,然后再讲述一些架构模式中的超类模式,作为本篇的结尾。
本篇的议题如下:
架构模式
设计模式
设计原则
设计模式
本篇文章主要是接着讨论的在业务层可以采用的或者常用的一些设计模式:
Factory Method
Decorator
State
Strategy
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
不为空。至于如何调用这些验证规则,在超类中已经实现了,此时业务类就“轻松”了很多
—
起码不用再次写那些相类似的代码了,实现了一定程度上的代码重用。
今天就讲到这里了,不正确之处,还望朋友们指出,见谅!
多谢支持!
本文转自yanyangtian51CTO博客,原文链接: http://blog.51cto.com/yanyangtian/434979
,如需转载请自行联系原作者