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


      为什么今天写这篇博客呢?
      主要是因为以前使用三层模式时,经常会出现一种问题,就是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         }

      目录结构:

      

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

  • 相关阅读:
    Mysql5.7 单表 500万数据迁移到新表的快速实现方案
    Jmeter5 实现多机集群压测(局域网组成多机集群)
    IDEA 配置datasource,提升编码效率,让你在 Mapper.xml 中编写sql可以飞起来~
    Logstash 6.4.3 导入 csv 数据到 ElasticSearch 6.4.3
    从零开始搭建一个从Win7环境备份至CentOS7的SVN双机备份环境
    实现logstash6.4.3 同步mysql数据到Elasticsearch6.4.3
    uEditor使用步骤
    动态添加a标签打开新网页
    vue给对象添加新的响应式属性
    vue下载excel
  • 原文地址:https://www.cnblogs.com/zcylife/p/3698087.html
Copyright © 2020-2023  润新知