领域驱动系列五模型驱动设计的构造块

一、简介

为了保证软件实现的简洁性,并且与模型保持一致,不管实际情况有多复杂,必须使用建模和设计的最佳实践,即让通过我们的编程技术(设计模型、指责驱动、契约式设计)充分地体现领域模型,并保持模型地健壮性和可扩展性,而不是单单地实现模型.某些决策设计能和模型紧紧地结合,这种结合要求我们注意每个元素地细节.

开发一个好的领域模型是一门艺术,而模型中的各个元素的实际设计和实现则相对系统化,将领域设计(也可以是软件系统中的其他关注点)与软件系统中的其他关注点(也可以是领域设计)分离使整个领域模型非常的清晰.根据不同模型的指责(特性)会使元素的意义更加鲜明.

二、实战

 上图展示的模型驱动设计的基本构造块,当然实际开发中可能不止这些内容,可能还会有施加在实体上的一些契约还有一些特殊的计算规则、可能还有有一些复杂的实体运算,这些运算可能还需要使用一些设计模式去设计等等.但这个基本的构造.

下面通过C#代码来实现一个简单的用户订单计价系统,如下:

项目结构如下:

代码如下:

    /// <summary>
    /// 用户聚合根
    /// </summary>
    public class UserAggregate
    {
        /// <summary>
        /// 抽象的用户
        /// </summary>
        public AbstractUser AbstractUser { get; set; }
    }
    /// <summary>
    /// 抽象的用户,里面定义用户的基本属性
    /// </summary>
    public abstract class AbstractUser
    {
        /// <summary>
        /// 值对象
        /// </summary>
        public abstract string UserName { get; set; }

        /// <summary>
        /// 值对象
        /// </summary>
        public abstract int Age { get; set; }

        /// <summary>
        /// 值对象 订单价格
        /// </summary>
        public abstract double OrderPrice { get; set; }
    }
    /// <summary>
    /// 计价策略类,具体的计算规则,随着业务的变化,可已重新实现
    /// </summary>
    public class UserPriceAggregateStartegy : IUserPriceAggregateStartegies
    {
        public double CalculatePrice(UserAggregate user)
        {
            double totalfee = 0;
            if (user.AbstractUser is WxUser)
            {
                //这里具体的优惠尺度可以去读取配置文件
                totalfee=user.AbstractUser.OrderPrice * 0.8;
            }
            else if (user.AbstractUser is NormalUser)
            {
                totalfee=user.AbstractUser.OrderPrice;
            }
            return totalfee;
        }
    }
    /// <summary>
    /// 普通用户
    /// </summary>
    public class NormalUser : AbstractUser
    {
        public  override string UserName { get; set; }

        public override int Age { get; set; }

        public override double OrderPrice { get; set; }
    }
    /// <summary>
    /// 微信用户
    /// </summary>
    public class WxUser: AbstractUser
    {
        public override string UserName { get; set; }

        public override int Age { get; set; }

        /// <summary>
        /// 微信用户的OpenId
        /// </summary>
        public string OpenId { get; set; }

        /// <summary>
        /// 值对象 订单价格
        /// </summary>
        public override double OrderPrice { get; set; }
    }
    /// <summary>
    /// 用户计价聚合根约束
    /// </summary>
    public interface IUserPriceAggregateFactory
    {
        UserAggregate CalculatePrice(IUserPriceAggregateStartegies startegies);
    }
    /// <summary>
    /// 用户聚合根工厂,按照计价策略生成对应的用户实体,这个类会暴露给外面的业务结构使用
    /// 将业务逻辑的处理交给工厂类,这样做的好处,是减轻控制器的压力,也符合领域驱动设计的理念
    /// </summary>
    public class UserPriceAggregateFactory: IUserPriceAggregateFactory
    {
        private UserPriceAggregateFactory() { }

        private UserAggregate _userAggregate;

        public UserPriceAggregateFactory(UserAggregate userAggregate)
        {
            _userAggregate = userAggregate;

        }

        public UserAggregate CalculatePrice(IUserPriceAggregateStartegies startegies)
        {
            var price=startegies.CalculatePrice(_userAggregate);
            _userAggregate.AbstractUser.OrderPrice = price;
            return _userAggregate;
        }
     
    }

控制台调用代码如下:

    class Program
    {
        static void Main(string[] args)
        {
            //拿到用户的输入
            var normalUser = new WxUser()
            {
                UserName = "小超",
                Age = 23,
                OrderPrice = 6
            };

            //组成业务聚合根
            var aggregare = new UserAggregate()
            {
                AbstractUser = normalUser
            };

            //生成用户计价类型的聚合根
            var user = new UserPriceAggregateFactory(aggregare);

            //生成具体的计价类型
            var startegy = new UserPriceAggregateStartegy();

            //生成计价过后的业务聚合根
            var priceUser = user.CalculatePrice(startegy);

            //随后将经过业务计算后的聚合根通过仓储初始化到数据库中
            //.....省略

            Console.WriteLine("当前用户的订单价格为:{0}", priceUser.AbstractUser.OrderPrice);
            Console.ReadKey();
        }
    }

根据上面的代码可以得出一个基本的领域模型,如下:

注意下图

这个过程可以随意组合,可以通过Facade模式,组合多种策略,然后施加到用户聚合根上,得到最终的聚合根

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券