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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM