今天我們通過一個“超市收銀”業務來作為我們的示例(雖然這個示例看上去不太正常,但是它確表述我們所需要的)。我們將從業務分析到業務建模然後最後的編碼來用“面向領域對象”的方式來做我們的項目。
好,我們開始吧!
一、業務分析
大家都去超市買過東西,對超市收銀業務都比較熟悉。什麼?你不熟?好吧,那我們找個收銀員給大家講解下(領域專家)。
收銀員小慧:哦,是這樣呢。顧客排隊銀帳我就收銀呢,我要使用收銀機呢。收銀機就能計算出要收的錢呢,我就掃一下呢,就OK了呢。然後就收銀了呢。
聽了小慧的講解,我們心中有了業務的概念了。我們這裏採用《業務關鍵字分析法》來找出此業務流程裏面的一些關係字:
商品
顧客
收銀員
收銀機
*收銀
*選商品
*收銀員使用收銀機
*收銀機掃商品計算金額
好了,列出這些“業務關鍵字”了,我們就可以建我們的對象模型了。
二、系統建模
上面我們分析出了一些“業務關鍵字”接下來我們分析這些業務關鍵字並深入他們的業務。
商品對象(Goods)。
屬性:商品名稱(GoodsName)、商品價格(GoodsPrice)。
行為:在這裏商品對象是沒有行為的,我們也可以叫它“值對象”。
顧客對象(Customer)。
屬性:顧客姓名(CustomerName)、顧客選購的商品(Goodss)
行為:選購想買的商品(LikeBuy)、聽收銀員説要收多少RMB(ListenAmount)
收銀員對象(Cashier)。
屬性:收銀員姓名(CashierName)
行為:收銀(CashierRegister)
收銀機對象(CashierRegister)。
屬性:收銀機編號(CashRegisterNo)
字段:總金額(_totalAmount)
行為:收銀(CashRegisters)、顯示收銀總額(ShowAmount)
有木有!有木有?有木有很直觀,這也就是面向對象分析的好處,因為對象就是對現實的抽象,我們現實中的事務可以很方便的用對象抽象出來。我們很容易發現,這和用表來描述這些業務模型顯然要不方便的多。表還只能描述屬性,造成了屬性與行為的分離。
三、代碼示例
商品對象
/// <summary>
/// 商品
/// </summary>
public class Goods
{
/// <summary>
/// 對象標識
/// </summary>
public Guid OKey { get; set; }
/// <summary>
/// 商品名稱
/// </summary>
public string GoodsName { get; set; }
/// <summary>
/// 商品價格
/// </summary>
public decimal GoodsPrice { get; set; }
}
顧客對象
/// <summary>
/// 顧客
/// </summary>
public class Customer
{
/// <summary>
/// 對象標識
/// </summary>
public Guid OKey { get; set; }
/// <summary>
/// 顧客姓名
/// </summary>
public string CustomerName { get; set; }
private List<Goods> _goodss = new List<Goods>();
/// <summary>
/// 顧客購買的商品
/// </summary>
public List<Goods> Goodss
{
get { return _goodss; }
set { _goodss = value; }
}
/// <summary>
/// 顧客選購商品
/// </summary>
/// <param name="goods">商品</param>
public void LikeBuy(Goods goods)
{
this._goodss.Add(goods);
}
/// <summary>
/// 聽收銀員應收多少錢
/// </summary>
/// <param name="amount"></param>
public void ListenAmount(decimal amount)
{
Console.WriteLine("我是[{0}],我買了{1}件商品。我共花了{2}元RMB。", this.CustomerName, this.Goodss.Count, amount.ToString("f2"));
}
收銀員對象
/// <summary>
/// 收銀員
/// </summary>
public class Cashier
{
/// <summary>
/// 對象標識
/// </summary>
public Guid OKey { get; set; }
/// <summary>
/// 收銀員姓名
/// </summary>
public string CashierName { get; set; }
/// <summary>
/// 收銀
/// </summary>
/// <param name="customer">顧客</param>
public void CashRegister(Customer customer)
{
//打開使用收銀機
CashRegister cashRegister = new CashRegister();
//對顧客的商品進行收銀機掃碼,收銀
foreach (var goods in customer.Goodss)
{
//使用收銀機掃商品進行收銀
cashRegister.CashRegisters(goods);
}
//通知顧客一共收多少錢
customer.ListenAmount(cashRegister.ShowAmount());
}
}
收銀機對象
/// <summary>
/// 對象標識
/// </summary>
public Guid OKey { get; set; }
/// <summary>
/// 收銀機編號
/// </summary>
public string CashRegisterNo { get; set; }
/// <summary>
/// 總價格
/// </summary>
private decimal _totalAmount { get; set; }
public CashRegister()
{
//收銀總額置0
this._totalAmount = 0;
}
/// <summary>
/// 收銀
/// </summary>
/// <param name="goods">商品</param>
public void CashRegisters(Goods goods)
{
this._totalAmount += goods.GoodsPrice;
}
/// <summary>
/// 顯示收銀總額
/// </summary>
/// <returns></returns>
public decimal ShowAmount()
{
return this._totalAmount;
}
模擬業務流程
//我們創建幾樣商品
Goods RedWine = new Goods() { GoodsName = "紅酒", GoodsPrice = 1800,OKey=Guid.NewGuid() };
Goods Condoms = new Goods() { GoodsName = "安全套", GoodsPrice = 35,OKey=Guid.NewGuid() };
//我們創建幾位顧客
Customer Chunge = new Customer() { CustomerName = "春哥", OKey = Guid.NewGuid() };
Customer Beianqi = new Customer() { CustomerName = "貝安琪", OKey = Guid.NewGuid() };
//當然,我們需要收銀員啊
Cashier CashierMM = new Cashier() { CashierName = "收銀員MM", OKey = Guid.NewGuid() };
//顧客逛了一圈,選了自己想要的商品
Chunge.LikeBuy(RedWine);
Beianqi.LikeBuy(RedWine);
Beianqi.LikeBuy(Condoms);
//顧客開始排隊結帳了
Queue<Customer> customerQueue = new Queue<Customer>();
customerQueue.Enqueue(Chunge);
customerQueue.Enqueue(Beianqi);
//隊伍過來,按先後順序挨個收銀嘍
foreach (var customer in customerQueue)
{
//收銀
CashierMM.CashRegister(customer);
}
顯示結果
上面的例子雖然不是很恰當,但是它也很好的像我們表達出了領域驅動分析問題、面向對象驅動開發的好處了。
最後大家回想一下,用數據庫表驅動的方式。分析這個業務會是什麼樣子的。。。。