關於業務邏輯和對象行爲的思考

  爲何今天寫這篇博客呢?
  主要是由於之前使用三層模式時,常常會出現一種問題,就是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         }

  目錄結構:

  

  好了,終於寫完了,你們要是若是有什麼建議和意見,歡迎積極評論!若是您以爲還不錯,幫忙點擊下推薦唄!!

相關文章
相關標籤/搜索