爲何今天寫這篇博客呢?
主要是由於之前使用三層模式時,常常會出現一種問題,就是BLL業務邏輯層沒有什麼業務邏輯,常常被用做表現層和DAL數據層的過分,總感受有跟沒有都同樣......,Model也只是用數據傳輸的載體,怎麼就以爲跟OOP思想扯不上關係,在我理解的OOP思想裏,對象應該是有生命力的纔對啊!!html
後來學習了領域驅動設計,使用EntityFramework CodeFirst重量級ORM,在看資料的過程當中,心理可美滋滋的了,應爲我以爲這纔是我心目中的OOP思想,領域對象有屬性,有行爲,有事件等等,很具備生命力;隨着項目運用,慢慢開始偏離軌道了,若是人生就是一個茶几,我就是上面的杯具,爲毛仍是和三層時的同樣,對象的生命力在哪裏,((‵□′)).....架構
做爲一個想成爲架構師的碼農來講,不行,絕對不行,我必須反思,檢討,反.......學習
下面是通過冥思苦想的一點點成果,和你們分享下,但願能獲得一些建議。ui
首先先用之前的寫法寫一個很是簡單下單處理,代碼以下:this
對象模型:spa
1.User用戶模型設計
1 public class User 2 : EntityBase 3 { 4 public string UserName { get; set; } 5 6 public string Email { get; set; } 7 8 public string Telephone { get; set; } 9 10 public Account Account { get; set; } 11 }
2.Account帳戶模型code
1 public class Account 2 : EntityBase 3 { 4 public Guid UserId { get; set; } 5 6 public double Amount { get; set; } 7 8 public DateTime ActiveLastTime { get; set; } 9 }
3.Product產品模型orm
1 public class Product 2 : EntityBase 3 { 4 public string Name { get; set; } 5 6 public double Price { get; set; } 7 8 public double Description { get; set; } 9 10 public int Number { get; set; } 11 12 public bool IsPutaway { get; set; } 13 }
4.Order訂單模型htm
public class Order : EntityBase { public string OrderNo { get; set; } public Guid ProductId { get; set; } public string ProductName { get; set; } public double Price { get; set; } public Guid UserId { get; set; } public DateTime CreateTime { get; set; } }
生成訂單的處理邏輯
1 public class OrderAppService 2 { 3 public void Create(Order order) 4 { 5 if (order == null) 6 throw new ArgumentNullException("order"); 7 8 order.OrderNo = NewOrderNo(); 9 order.CreateTime = DateTime.Now; 10 11 //進行建立訂單 12 } 13 14 private string NewOrderNo() 15 { 16 return ""; 17 } 18 }
表現層進行生成訂單
1 public JsonResult CreateOrder(Guid productId) 2 { 3 //這裏數據獲取就省略了哈... 4 Web.Domain.UserModule.User user = null; 5 Web.Domain.ProductModule.Product product = null; 6 7 if (product.Number > 0) 8 return Json(new { success = false, error = string.Format("\"{0}\" 該產品庫存不足,沒法購買。", product.Name) }); 9 10 if (!product.IsPutaway) 11 return Json(new { success = false, error = string.Format("\"{0}\" 該產品尚未上架或者暫時下架,若有問題請諮詢客服人員。", product.Name) }); 12 13 if (user.Account.Amount < product.Price) 14 return Json(new { success = false, error = "您的金額不足,請先進行充值,再購買。" }); 15 16 Order order = new Order 17 { 18 ProductId = product.Id, 19 ProductName = product.Name, 20 Price = product.Price, 21 UserId = user.Id 22 }; 23 24 try 25 { 26 Web.Application.OrderModule.OrderAppService service = new Web.Application.OrderModule.OrderAppService(); 27 service.Create(order); 28 } 29 catch 30 { 31 return Json(new { success = false, error = "系統出錯了,請稍後在進行購買。" }); 32 } 33 return Json(new { success = true }); 34 }
OK,之前的寫法就是這樣,不知道有沒有人和我寫的差很少,(●'◡'●)....
下面是我根據本身的思路作的一些改進,同時引進前面一篇《提高Boolean和out相結合的用戶體驗》中的Can狀態對象。
首先意識到的是表現層的CreateOrder下有不少訂單處理的業務邏輯,應該放置在業務邏輯OrderAppService中,代碼等下貼出。
再觀察業務邏輯中的3個if,我以爲應該以擬人的方式進行思考,以下,
1.product.Number < 0 : 咱們應該問產品:"你如今還有庫存嗎?" 產品作出回答:"沒有!";產品作出的回答屬於產品的一個行爲,那我以爲應該給它定義一個行爲:Can HasNumber();
2.!product.IsPutaway : 問:"你如今什麼狀態我能購買嗎?" 答:"下架中,不能購買!";雖然這裏只有上下架的狀態,後期可能會拓展,全部也給他定義一個行爲:Can IsEnabled();
3.我的以爲這兩個if都是詢問產品能不能買,可能之後還會有其餘限制,全部我以爲應該讓產品直接回答咱們能不能購買,讓它本身一次性檢查:Can CanBuying();
4.User.Account.Amount < product.Price:這個應該問用戶:」我須要這麼多的錢你有嗎?「,用戶說:」沒有!「,Can HasMoney(double amount);
下面來看看改造後的模型:
public class Product : EntityBase { public string Name { get; set; } public double Price { get; set; } public double Description { get; set; } public int Number { get; set; } public bool IsPutaway { get; set; } /// <summary> /// 有沒有庫存 /// </summary> /// <returns></returns> public Can HasNumber() { if (this.Number < 0) return string.Format("\"{0}\" 該產品庫存不足,沒法購買。", this.Name); return true; } /// <summary> /// 當前狀態是否支持購買 /// </summary> /// <returns></returns> public Can IsEnabled() { if (!this.IsPutaway) return string.Format("\"{0}\" 該產品尚未上架或者暫時下架,若有問題請諮詢客服人員。", this.Name); return true; } /// <summary> /// 當前產品是否能夠購買 /// </summary> /// <returns></returns> public Can CanBuying() { var hasNumber = this.HasNumber(); if (!hasNumber) return hasNumber; var isEnabled = this.IsEnabled(); if (!isEnabled) return isEnabled; return true; } } public class User : EntityBase { public string UserName { get; set; } public string Email { get; set; } public string Telephone { get; set; } public Account Account { get; set; } /// <summary> /// 是否有指定額度的錢 /// </summary> /// <param name="amount">指定額度的錢</param> public Can HasMoney(double amount) { if (this.Account == null) throw new MemberAccessException("帳戶未被實例化"); return this.Account.HasMoney(amount); } } public class Account : EntityBase { public Guid UserId { get; set; } public double Amount { get; set; } public DateTime ActiveLastTime { get; set; } /// <summary> /// 是否有指定額度的錢 /// </summary> /// <param name="amount">指定額度的錢</param> public Can HasMoney(double amount) { if (this.Amount < amount) return "您的金額不足,請先進行充值,再購買。"; return true; } }
public class Order : EntityBase { public Order(Guid productId, string productName, double price, Guid userId) { this.ProductId = productId; this.ProductName = productName; this.Price = price; this.UserId = userId; this.CopyToNewOrder(); } public string OrderNo { get; private set; } public Guid ProductId { get; set; } public string ProductName { get; set; } public double Price { get; set; } public Guid UserId { get; set; } public DateTime CreateTime { get; private set; } /// <summary> /// 拷貝爲新建立的訂單 /// </summary> public void CopyToNewOrder() { this.OrderNo = this.NewOrderNo(); this.CreateTime = DateTime.Now; } private string NewOrderNo() { return ""; } }
而後我以爲應該學習下CQRS查詢與命令分離的思路,爲業務邏輯建立判斷邏輯的統一存儲以下:
1 public static class OrderAppLogic 2 { 3 /// <summary> 4 /// 是否能夠建立訂單 5 /// </summary> 6 /// <param name="user">用戶</param> 7 /// <param name="product">產品</param> 8 /// <returns></returns> 9 public static Can CanCreateOrder(User user, Product product) 10 { 11 Can canCreateOrder = true; 12 13 if(!(canCreateOrder = product.CanBuying())) 14 return canCreateOrder; 15 16 if(!(canCreateOrder = user.HasMoney(product.Price))) 17 return canCreateOrder; 18 19 return canCreateOrder; 20 } 21 }
OrderAppService 就挺簡單的了
1 public Can Create(User user, Product product) 2 { 3 if (user == null) 4 throw new ArgumentNullException("user"); 5 6 if (product == null) 7 throw new ArgumentNullException("product"); 8 9 Can flag = true; 10 11 if (!(flag = OrderAppLogic.CanCreateOrder(user, product))) 12 return flag; 13 14 Order order = new Order(product.Id, product.Name, product.Price, user.Id); 15 16 //進行建立 17 18 return flag; 19 }
表現層代碼就更簡單了
1 public JsonResult CreateOrder(Guid productId) 2 { 3 //這裏數據獲取就省略了哈... 4 Web.Domain.UserModule.User user = null; 5 Web.Domain.ProductModule.Product product = null; 6 7 try 8 { 9 Web.Application.OrderModule.OrderAppService service = new Web.Application.OrderModule.OrderAppService(); 10 var result = service.Create(user, product); 11 return Json(new { success = (bool)result, error = result.Error }); 12 } 13 catch 14 { 15 return Json(new { success = false, error = "系統出錯了,請稍後在進行購買。" }); 16 } 17 }
目錄結構:
好了,終於寫完了,你們要是若是有什麼建議和意見,歡迎積極評論!若是您以爲還不錯,幫忙點擊下推薦唄!!