最近面向领域的知识挺火,我也来插一腿。说说我平时做项目时候用到的开发方式,以下代码为伪代码,主要展示一下我现在的开发方式供大家讨论,系统中不考虑持久、UI、AOP和IOC等方面内容。
说到.NET社区的“开发方式”就不得不提一下Petshop了,可以说Petshop真是影响了.NET的一代人。以至于三层成了.NET这边流行的标准的开发方式。但是要说一下Petshop是数据库驱动业务核心的过程式开发,也正是它也毒害了一批人。
下面我们以一个最常见也是大家比较熟的下定单来简单看一下。首先是系统的几个领域类:
应牧章的要求,加上类之间的关系:这里的关系很简单,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
}
接下来看看我这个伪代码的项目结构。做的很简单,简单明快的架构就是好的架构,不要把架构搞的很复杂。
Domain:领域层,里面放的是领域对象。这个层对其它层没有依赖
Repository:持久层,对领域对象进行持久。里面可以有级存和DB等。这个层依赖Domain
Services:应用程序服务,这个名字喜好着起吧。我们可以把它理解为业务逻辑层,当然这个业务逻辑是对一个功能更粗粒度的API。里面会调用依赖的领域对象进行业务组合达到业务需求。当然对对象的持久也是这里来做的。这个层依赖Domain和Repository
Web:UI层,调用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里面的是伪代码,就不发了。
工作呢,写的很粗略。最后说一点,其实面向领域开发通过这些代码是看不出本质的。我在这总结一下。
把你的开发关注点提到类(对象)上来,不要把关注点放到数据库(表)上。
PS:我也是存储过程(业务)反对派