Anaemic Domain Model (ADM) And Rich Domain Model (RDM)

2023-02-25

筆記 Anaemic Domain Model (ADM) 與 Rich Domain Model 的優缺點。

logo

說明

Anaemic Domain Model

Anaemic Domain Model (ADM) 是一種將業務邏輯與資料庫操作分離的程式設計模式,通常是將所有的業務邏輯都放在 Service 層中,而 Entity 或 DTO 則只是一個純資料容器。以下是 ADM 的優點與缺點:

✔️ 優點

  • 簡單易學:ADM 模式簡單,不需要太多的概念,對於新手來說比較容易上手。
  • 易於測試:由於業務邏輯都放在 Service 層中,業務邏輯和資料操作分離,因此容易進行單元測試。

❌ 缺點

  • 違反 OOP:ADM 中的 Entity 或 DTO 只是純資料容器,而所有的業務邏輯都在 Service 層中,這導致了 ADM 違反了 OOP 或者是說不那麼地符合 OOP 😗
  • 維護困難:由於業務邏輯都放在 Service 層中,當業務邏輯變得複雜時,Service 層會變得越來越龐大,維護困難。

Entity.cs / DTO.cs

public class Product {
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Service.cs

public class ProductService {
    private readonly DbContext _dbContext;

    public ProductService(DbContext dbContext) {
        _dbContext = dbContext;
    }

    public List<Product> GetAllProducts() {
        return _dbContext.Products.ToList();
    }

    public void CreateProduct(Product product) {
        _dbContext.Products.Add(product);
        _dbContext.SaveChanges();
    }
}

public class ProductController : Controller {
    private readonly ProductService _productService;

    public ProductController(ProductService productService) {
        _productService = productService;
    }

    public IActionResult Index() {
        var products = _productService.GetAllProducts();
        return View(products);
    }

    [HttpPost]
    public IActionResult Create(Product product) {
        _productService.CreateProduct(product);
        return RedirectToAction("Index");
    }
}

Rich Domain Model

✔️ 優點

  • 符合 OOPRDM 能夠將業務邏輯與資料庫操作整合在同一個類別中,符合 OOP,也有助於提高程式碼的可讀性和可維護性。
  • 降低耦合度:由於 RDM 中的類別具有業務邏輯和資料操作的功能,因此不需要像 ADM 一樣依賴 Service 層,降低了系統中各個模組之間的耦合度。

❌ 缺點

  • 學習曲線較高:相較於 ADM,RDM 需要更多的 OOP 學習與設計。
  • 單元測試較難:RDM 中的類別具有業務邏輯和資料操作的功能,因此測試需要涵蓋更多的層次,較難進行單元測試。

Domain.cs

public class Product {
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }

    public void Create() {
        // Business Logic
    }

    public void Update() {
        // Business Logic
    }

    public void Delete() {
        // Business Logic
    }
}

Controller.cs

// Controller
public class ProductController : Controller {
    private readonly DbContext _dbContext;

    public ProductController(DbContext dbContext) {
        _dbContext = dbContext;
    }

    public IActionResult Index() {
        var products = _dbContext.Products.ToList();
        return View(products);
    }

    [HttpPost]
    public IActionResult Create(Product product) {
        product.Create();
        _dbContext.Products.Add(product);
        _dbContext.SaveChanges();
        return RedirectToAction("Index");
    }

    [HttpPost]
    public IActionResult Edit(Product product) {
        product.Update();
        _dbContext.Products.Update(product);
        _dbContext.SaveChanges();
        return RedirectToAction("Index");
    }

    [HttpPost]
    public IActionResult Delete(int id) {
        var product = _dbContext.Products.Find(id);
        product.Delete();
        _dbContext.Products.Remove(product);
        _dbContext.SaveChanges();
        return RedirectToAction("Index");
    }
}

參考資料

Anemic data models (ADM) VS Rich Data Models (RDM) in C#

Anaemic Domain Model vs. Rich Domain Model

相關連結

ASP.NET MVC 從無到有打造一個應用系統

Visual Studio 入門教學