zoukankan      html  css  js  c++  java
  • ABP VNext 微服务搭建入门(2)-- 从领域开始对象建模

    DDD的好处

    相对于传统的数据驱动设计,基于领域驱动设计的代码可以提现通用语言,更具可读性,更能准确表达业务。

    一、确定领域、拆分子域

    常见电商系统拆分

    领域:电商

    子域:销售、商品、用户、商家、订单等

    核心域:销售

    通用域:非业务模块,如日志子域

    支撑域:物流、商品等

    二、限界上下文(语境)

    当划分子域之后,每个子域都对应有各自的上下文。在销售子域和商品子域所在的上下文语境中,商品就是商品,无二义性。但如果子域对应多个上下文的时候,就要考虑一下是不是子域能否继续划分。

    *三、领域对象

    领域对象是服务的提供方,而不是数据容器,提供业务行为,而不是数据。

    领域模型(实体)

    领域模型在代码中提现为实体,映射到真实数据表。实体有唯一标识,具有可变性。如订单就是唯一的,且订单状态会随业务行为而改变。
    领域模型应该是充血模型而不是贫血模型。贫血模型只包含属性的 get set 方法。充血模型更加丰富,包含业务逻辑。
    abp已经定义了 Entity 系列类,实现即可。

    值对象

    值对象没有唯一标识,且不可变。如订单地址就是不可变,而收货地址是可变的且拥有唯一标识。abp已经定义了 ValueObject 类,实现即可。

    聚合根

    聚合根是主实体,子实体都不可能孤立存在,它们必须依附于一个聚合根存在。如订单就是聚合根,物流信息是依赖于订单的子实体。abp已经定义了 AggregateRoot 系列类,实现即可。

    聚合

    一个聚合中可以包含多个实体和值对象。聚合是持久化的基本单位,它和仓储具有一一对应的关系。如一个完整的订单聚合就包含物流等信息。

    示例

    public class BlogPost: AggregateRoot<int>
    {
    	private BlogPost()
    	{
    		// just for EF
    	}
                
            //使用参数化的构造函数可以确保我们的领域模型在实例化时有效
    	public BlogPost(string title, string summary, string body)
    	{
    		if (string.IsNullOrWhiteSpace(title))
    		{
    			throw new ArgumentException("Title is required");
    		}
    
    		...
    
    		Title = title;
    		Summary = summary;
    		Body = body;
    		DateAdded = DateTime.UtcNow;
    	}
    	
            //引入更改状态的方法使我们能够集中业务逻辑并简化调用代码
    	public void Publish()
    	{
    		if (Status == BlogPostStatus.Draft || Status == BlogPostStatus.Archived)
    		{
    			if (Status == BlogPostStatus.Draft)
    			{
    				DatePublished = DateTime.UtcNow;
    			}
    
    			Status = BlogPostStatus.Published;
    		}
    	}
    
            private string title;
    
    	[Required]
    	public string Title
    	{
    		get { return title; }
    		set
    		{
                            //内部集中校验
    			if (string.IsNullOrWhiteSpace(value))
    			{
    				throw new ArgumentException("Title must contain a value");
    			}
    
    			title = value;
    		}
    	}
    
    	[Required]
    	[StringLength(500)]
    	//清除公共属性setter确保我们的模型在其整个生命周期内保持有效状态
    	public string Summary { get;private set; }
    
    	[Required]
    	public string Body { get;private set; }
    
    	public DateTime DateAdded { get;private set; }
    
    	public DateTime? DatePublished { get;private set; }
    
    	public BlogPostStatus Status { get;private set; }
    
    	//使用值对象 生成 AdvertisingFee_Currency 和 AdvertisingFee_Amount 列
    	public Money AdvertisingFee { get; private set; }
        ...
    }
    
    public class Money:ValueObject
    {
        [StringLength(3)]
        public string Currency { get; private set; }
    
        public int Amount { get; private set; }
    
        private Money()
        {
            // just for EF
        }
    
        public Money(string currency, int amount)
        {
            // todo validation
            Currency = currency;
            Amount = amount;
        }
    
         protected override IEnumerable<object> GetAtomicValues()
         {
                 yield return Currency;
                 yield return Amount;
         }
    }
    
    public class BlogContext : DbContext
    {
        ...
        public DbSet<BlogPost> BlogPosts { get; set; }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<BlogPost>().OwnsOne(x => x.AdvertisingFee);
        }
    }
    
    

    参考

    https://www.cnblogs.com/sheng-jie/category/997516.html

  • 相关阅读:
    ThetaSome_ThetaAll子查询
    BMP文件解析
    IN-子查询
    由顶点坐标计算任意多边形面积
    Java入门——多态
    使用Notepad++开发Java程序
    C#利用VUDP.cs开发网络通讯应用例程
    C#利用Vini.cs操作INI文件
    RC522射频卡读写模块驱动(仅读取)
    Tupper自我指涉公式生成器
  • 原文地址:https://www.cnblogs.com/zk-ljc/p/14092598.html
Copyright © 2011-2022 走看看