关于业务逻辑和对象行为的思考

  为什么今天写这篇博客呢?
  主要是因为以前使用三层模式时,经常会出现一种问题,就是BLL业务逻辑层没有什么业务逻辑,经常被用作表现层和DAL数据层的过度,总感觉有跟没有都一样......,Model也只是用数据传输的载体,怎么就觉得跟OOP思想扯不上关系,在我理解的OOP思想里,对象应该是有生命力的才对啊!!

  后来学习了领域驱动设计,使用EntityFramework CodeFirst重量级ORM,在看资料的过程中,心理可美滋滋的了,应为我觉得这才是我心目中的OOP思想,领域对象有属性,有行为,有事件等等,很具有生命力;随着项目运用,慢慢开始偏离轨道了,如果人生就是一个茶几,我就是上面的杯具,为毛还是和三层时的一样,对象的生命力在哪里,((‵□′)).....

  作为一个想成为架构师的码农来说,不行,绝对不行,我必须反思,反省,反.......

  下面是经过左思右想的一点点成果,和大家分享下,希望能得到一些建议。

  首先先用以前的写法写一个非常简单下单处理,代码如下:

  对象模型:

  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账户模型

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产品模型

 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订单模型

    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         }

  目录结构:

  关于业务逻辑和对象行为的思考

  好了,终于写完了,大家要是如果有什么建议和意见,欢迎积极评论!如果您觉得还不错,帮忙点击下推荐呗!!

你可能感兴趣的:(对象)