Mô hình tên miền giàu so với thiếu máu [đã đóng]


90

Tôi đang quyết định xem mình có nên sử dụng Mô hình tên miền phong phú thay vì Mô hình tên miền thiếu máu hay không và tìm kiếm các ví dụ điển hình về hai mô hình này.

Tôi đã và đang xây dựng các ứng dụng web bằng Mô hình miền Anemic, được hỗ trợ bởi hệ thống lớp Dịch vụ -> Kho lưu trữ -> Lưu trữ , sử dụng FluentValidation để xác thực BL và đưa tất cả BL của tôi vào lớp Dịch vụ.

Tôi đã đọc cuốn sách DDD của Eric Evan, và anh ấy (cùng với Fowler và những người khác) dường như nghĩ rằng Mô hình miền thiếu máu là một kiểu chống đối.

Vì vậy, tôi chỉ thực sự muốn tìm hiểu sâu hơn về vấn đề này.

Ngoài ra, tôi thực sự đang tìm kiếm một số ví dụ hay (cơ bản) về Mô hình tên miền phong phú và những lợi ích so với Mô hình tên miền thiếu máu mà nó cung cấp.


Bạn cũng có thể muốn xem blog
Japheth Ongeri - inkalimeva

14
DDD> ADM , ADM> DDD , DDD> ADM , ADM> DDD , ADM + DDD ... DDD / ADM, hoặc không đồng ý về thiết kế phần mềm !
sp00m

Dưới đây là một ví dụ về cách tránh mô hình miền thiếu máu: medium.com/@wrong.about/…
Vadim Samokhin

9
Thật buồn cười khi câu hỏi này có thể được trả lời bằng một liên kết duy nhất đến một dự án thế giới thực được tài trợ bởi tổ chức thực. Sau 5 năm, không có câu trả lời tốt, IMO. Nói chuyện là rẻ. Cho tôi xem mã.
Mateusz Stefek

Câu trả lời:


56

Sự khác biệt là một mô hình thiếu máu phân tách logic khỏi dữ liệu. Logic thường được đặt trong các lớp học được đặt tên **Service, **Util, **Manager, **Helpervà vân vân. Các lớp này thực hiện logic diễn giải dữ liệu và do đó lấy mô hình dữ liệu làm đối số. Ví dụ

public BigDecimal calculateTotal(Order order){
...
}

trong khi cách tiếp cận miền phong phú đảo ngược điều này bằng cách đặt logic diễn giải dữ liệu vào mô hình miền phong phú. Do đó, nó đặt logic và dữ liệu lại với nhau và một mô hình miền phong phú sẽ trông như thế này:

order.getTotal();

Điều này có ảnh hưởng lớn đến tính nhất quán của đối tượng. Vì logic diễn giải dữ liệu bao bọc dữ liệu (dữ liệu chỉ có thể được truy cập thông qua các phương thức đối tượng) nên các phương thức có thể phản ứng với các thay đổi trạng thái của dữ liệu khác -> Đây là những gì chúng ta gọi là hành vi.

Trong một mô hình thiếu máu, các mô hình dữ liệu không thể đảm bảo rằng chúng ở trạng thái hợp pháp trong khi chúng có thể ở trong một mô hình miền phong phú. Mô hình miền phong phú áp dụng các nguyên tắc OO như đóng gói, ẩn thông tin và đưa dữ liệu và logic lại với nhau và do đó mô hình thiếu máu là một mô hình phản đối từ quan điểm OO.

Để có cái nhìn sâu sắc hơn, hãy xem blog của tôi https://www.link-intersystems.com/blog/2011/10/01/anemic-vs-rich-domain-models/


15
Giả sử việc tính toán tổng giá của một đơn đặt hàng bao gồm: 1) Áp dụng chiết khấu tùy thuộc vào việc khách hàng là thành viên của một trong nhiều chương trình khách hàng thân thiết có thể có. 2) Áp dụng giảm giá cho các đơn hàng có một nhóm mặt hàng cụ thể với nhau tùy thuộc vào chiến dịch tiếp thị hiện tại của cửa hàng. 3) Tính thuế trong đó số thuế phụ thuộc vào từng mặt hàng cụ thể của đơn hàng. Theo bạn, tất cả logic này sẽ thuộc về đâu? Bạn có thể vui lòng đưa ra một ví dụ mã giả đơn giản. Cảm ơn bạn!
Nik

4
@Nik Trong mô hình phong phú, Đơn đặt hàng sẽ có tham chiếu đến đối tượng Khách hàng và đối tượng Khách hàng sẽ tham chiếu đến Chương trình khách hàng thân thiết. Do đó, Đơn hàng sẽ có quyền truy cập vào tất cả thông tin cần thiết mà không cần tham chiếu rõ ràng đến những thứ như dịch vụ và kho lưu trữ để lấy thông tin đó. Tuy nhiên, có vẻ như dễ gặp phải trường hợp tham chiếu theo chu kỳ đang xảy ra. Tức là Đơn đặt hàng tham chiếu đến Khách hàng, Khách hàng có một danh sách tất cả các Đơn đặt hàng Tôi nghĩ đây có thể là một phần lý do tại sao mọi người thích Anemic bây giờ hơn.
nghiền nát

3
@crush Cách tiếp cận bạn mô tả hoạt động thực sự tốt. Có một cách bắt. Có thể chúng tôi lưu trữ các thực thể trong một DB. Vì vậy, để tính toán tổng số đơn đặt hàng, chúng ta phải tìm nạp Đơn hàng, Khách hàng, Chương trình khách hàng thân thiết, Chiến dịch tiếp thị, Bảng thuế từ DB. Cũng hãy xem xét, một Khách hàng có một tập hợp các Đơn đặt hàng, một Chương trình Khách hàng thân thiết có một tập hợp các Khách hàng, v.v. Nếu chúng ta tìm nạp tất cả những thứ này một cách ngây thơ, chúng ta sẽ tải toàn bộ DB vào RAM. Tất nhiên, điều này không khả thi, vì vậy chúng tôi chỉ tải dữ liệu có liên quan từ DB ... 1/2
Nik

3
@Nik "Nếu chúng ta tự tìm nạp tất cả những thứ này, chúng ta sẽ tải toàn bộ DB vào RAM." Đó cũng là một trong những nhược điểm chính của mô hình giàu có trong tâm trí tôi. Mô hình phong phú là tốt cho đến khi miền của bạn phát triển lớn và phức tạp, sau đó bạn bắt đầu gặp phải các hạn chế về cơ sở hạ tầng. Tuy nhiên, đó là lúc mà ORM của lazy-load có thể trợ giúp. Tìm một cái tốt và bạn có thể giữ lại các mô hình phong phú trong khi không tải toàn bộ DB vào bộ nhớ khi bạn chỉ cần 1/5 của nó. Điều đó nói lên rằng, tôi có xu hướng sử dụng Mô hình thiếu máu với CQRS sau nhiều năm quay đi quay lại giữa thiếu máu và giàu.
nghiền nát

2
Một điều khác cần xem xét là nơi logic miền kinh doanh của bạn sống. Theo quan điểm của tôi, ngày càng có nhiều nhà phát triển chuyển nó ra khỏi cơ sở dữ liệu và sang các ứng dụng mà nó thuộc về. Nhưng nếu bạn bị mắc kẹt trong một tình huống mà công ty của bạn yêu cầu logic nghiệp vụ phải ở trong lớp cơ sở dữ liệu (các thủ tục được lưu trữ), thì bạn gần như chắc chắn sẽ không được hưởng lợi từ việc thêm logic đó trong một mô hình miền phong phú. Trên thực tế, bạn có thể đang tự thiết lập để gặp xung đột trong đó các thủ tục được lưu trữ có các quy tắc khác với lớp miền của ứng dụng của bạn ...
nghiền nát

53

Bozhidar Bozhanov dường như lập luận ủng hộ mô hình thiếu máu trong bài đăng trên blog này .

Đây là bản tóm tắt mà anh ấy trình bày:

  • các đối tượng miền không được quản lý theo mùa xuân (IoC), chúng không được có DAO hoặc bất kỳ thứ gì liên quan đến cơ sở hạ tầng được đưa vào

  • các đối tượng miền có các đối tượng miền mà chúng phụ thuộc vào được thiết lập bởi hibernate (hoặc cơ chế duy trì)

  • các đối tượng miền thực hiện logic nghiệp vụ, như ý tưởng cốt lõi của DDD, nhưng điều này không bao gồm các truy vấn cơ sở dữ liệu hoặc CRUD - chỉ các hoạt động trên trạng thái bên trong của đối tượng

  • hiếm khi cần đến DTO - các đối tượng miền chính là DTO trong hầu hết các trường hợp (giúp lưu một số mã soạn sẵn)

  • các dịch vụ thực hiện các hoạt động CRUD, gửi email, điều phối các đối tượng miền, tạo báo cáo dựa trên nhiều đối tượng miền, thực thi truy vấn, v.v.

  • lớp dịch vụ (ứng dụng) không quá mỏng nhưng không bao gồm các quy tắc nghiệp vụ nội tại đối với các đối tượng miền

  • nên tránh tạo mã. Tính trừu tượng, các mẫu thiết kế và DI nên được sử dụng để khắc phục nhu cầu tạo mã, và cuối cùng - để loại bỏ sự trùng lặp mã.

CẬP NHẬT

Gần đây tôi đọc này bài báo mà những người ủng hộ giả của sau một loại phương pháp lai - đối tượng miền có thể trả lời câu hỏi khác nhau hoàn toàn dựa trên tình trạng của họ (mà trong trường hợp của mô hình hoàn toàn thiếu máu có thể sẽ được thực hiện trong các lớp dịch vụ)


11
Tôi không thể trích dẫn từ bài báo đó rằng Bozho dường như lập luận ủng hộ mô hình miền thiếu máu. lớp dịch vụ (ứng dụng) không quá mỏng, nhưng không bao gồm các quy tắc nghiệp vụ nội tại đối với các đối tượng miền . Những gì tôi hiểu là, các đối tượng miền nên chứa logic nghiệp vụ nội tại của chúng, nhưng chúng không được chứa bất kỳ logic cơ sở hạ tầng nào khác . Đối với tôi, cách tiếp cận này không giống như một mô hình miền thiếu máu.
Utku

8
Cũng cái này: các đối tượng miền thực hiện logic nghiệp vụ, như ý tưởng cốt lõi của DDD, nhưng điều này không bao gồm các truy vấn cơ sở dữ liệu hoặc CRUD - chỉ các hoạt động trên trạng thái bên trong của đối tượng . Những tuyên bố này dường như không ủng hộ mô hình miền thiếu máu chút nào. Họ chỉ nói rằng logic cơ sở hạ tầng không nên được ghép nối với các đối tượng miền. Ít nhất đó là những gì tôi hiểu.
Utku

@Utku Theo quan điểm của tôi, có vẻ khá rõ ràng rằng Bozho ủng hộ một kiểu lai giữa hai mô hình, một kiểu lai mà tôi có thể nói là gần với mô hình thiếu máu hơn là mô hình giàu.
geoand

40

Quan điểm của tôi là:

Mô hình miền thiếu máu = các bảng cơ sở dữ liệu được ánh xạ tới các đối tượng (chỉ giá trị trường, không có hành vi thực)

Mô hình miền phong phú = tập hợp các đối tượng thể hiện hành vi

Nếu bạn muốn tạo một ứng dụng CRUD đơn giản, có thể một mô hình thiếu máu với khung MVC cổ điển là đủ. Nhưng nếu bạn muốn thực hiện một số loại logic, mô hình thiếu máu có nghĩa là bạn sẽ không lập trình hướng đối tượng.

* Lưu ý rằng hành vi của đối tượng không liên quan gì đến tính bền bỉ. Một lớp khác (Người lập bản đồ dữ liệu, Kho lưu trữ, v.v.) chịu trách nhiệm cho các đối tượng miền tồn tại.


5
Xin lỗi vì sự thiếu hiểu biết của tôi, nhưng làm thế nào để mô hình tên miền phong phú có thể tuân theo SOLID Princecipe nếu bạn đặt tất cả logic liên quan đến Thực thể trong lớp. Điều này vi phạm nguyên tắc SOLID, chính xác là 'S', viết tắt của khả năng đáp ứng duy nhất, nói rằng một lớp chỉ nên làm một việc và làm đúng.
redigaffi 13/1017

5
@redigaffi Nó phụ thuộc vào cách bạn định nghĩa "một điều". Hãy xem xét một lớp học với hai thuộc tính và hai phương pháp: x, y, sumdifference. Đó là bốn điều. Hoặc bạn có thể tranh luận đó là phép cộng và phép trừ (hai thứ). Hoặc bạn có thể tranh luận rằng đó là toán học (một điều). Có rất nhiều bài đăng trên blog về cách bạn tìm thấy sự cân bằng trong việc áp dụng SRP. Đây là một: hackernoon.com/…
Rainbolt

2
Trong DDD, khả năng tương ứng đơn có nghĩa là một lớp / mô hình có thể quản lý trạng thái của chính nó mà không gây ra bất kỳ tác dụng phụ nào cho toàn bộ hệ thống. Theo kinh nghiệm của tôi, bất kỳ định nghĩa nào khác đều dẫn đến những cuộc tranh luận triết học tẻ nhạt.
ZombieTfk

12

Trước hết, tôi sao chép đã dán câu trả lời từ bài viết này http://msdn.microsoft.com/en-gb/magazine/dn385704.aspx

Hình 1 cho thấy Mô hình miền Anemic, về cơ bản là một lược đồ với các bộ định tuyến và bộ định tuyến.

Figure 1 Typical Anemic Domain Model Classes Look Like Database Tables

public class Customer : Person
{
  public Customer()
  {
    Orders = new List<Order>();
  }
  public ICollection<Order> Orders { get; set; }
  public string SalesPersonId { get; set; }
  public ShippingAddress ShippingAddress { get; set; }
}
public abstract class Person
{
  public int Id { get; set; }
  public string Title { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string CompanyName { get; set; }
  public string EmailAddress { get; set; }
  public string Phone { get; set; }
}

Trong mô hình phong phú hơn này, thay vì chỉ để lộ các thuộc tính có thể đọc và ghi vào, bề mặt công khai của Khách hàng được tạo thành từ các phương thức rõ ràng.

Figure 2 A Customer Type That’s a Rich Domain Model, Not Simply Properties

public class Customer : Contact
{
  public Customer(string firstName, string lastName, string email)
  {
    FullName = new FullName(firstName, lastName);
    EmailAddress = email;
    Status = CustomerStatus.Silver;
  }
  internal Customer()
  {
  }
  public void UseBillingAddressForShippingAddress()
  {
    ShippingAddress = new Address(
      BillingAddress.Street1, BillingAddress.Street2,
      BillingAddress.City, BillingAddress.Region,
      BillingAddress.Country, BillingAddress.PostalCode);
  }
  public void CreateNewShippingAddress(string street1, string street2,
   string city, string region, string country, string postalCode)
  {
    ShippingAddress = new Address(
      street1,street2,
      city,region,
      country,postalCode)
  }
  public void CreateBillingInformation(string street1,string street2,
   string city,string region,string country, string postalCode,
   string creditcardNumber, string bankName)
  {
    BillingAddress = new Address      (street1,street2, city,region,country,postalCode );
    CreditCard = new CustomerCreditCard (bankName, creditcardNumber );
  }
  public void SetCustomerContactDetails
   (string email, string phone, string companyName)
  {
    EmailAddress = email;
    Phone = phone;
    CompanyName = companyName;
  }
  public string SalesPersonId { get; private set; }
  public CustomerStatus Status { get; private set; }
  public Address ShippingAddress { get; private set; }
  public Address BillingAddress { get; private set; }
  public CustomerCreditCard CreditCard { get; private set; }
}

2
Có một vấn đề với các phương thức vừa tạo đối tượng vừa gán thuộc tính với đối tượng mới được tạo. Chúng làm cho mã ít mở rộng và linh hoạt hơn. 1) Điều gì sẽ xảy ra nếu người tiêu dùng mã không muốn tạo Address, nhưng ExtendedAddress, được kế thừa từ Address, với một số thuộc tính bổ sung? 2) Hoặc thay đổi CustomerCreditCardcác tham số hàm tạo để lấy BankIDthay vì BankName?
Lightman

Điều gì đang tạo một địa chỉ yêu cầu các dịch vụ bổ sung hơn những gì tạo ra đối tượng? Bạn còn lại với phương pháp tiêm để nhận được các dịch vụ đó. Nếu đó là nhiều dịch vụ thì sao?
nghiền nát

8

Khi tôi sử dụng để viết các ứng dụng máy tính để bàn nguyên khối, tôi đã xây dựng các mô hình miền phong phú, tôi thường thích xây dựng chúng.

Bây giờ tôi viết các microservices HTTP nhỏ, có ít mã nhất có thể, bao gồm cả DTO thiếu máu.

Tôi nghĩ DDD và đối số thiếu sáng suốt này bắt nguồn từ kỷ nguyên ứng dụng máy chủ hoặc máy tính để bàn nguyên khối. Tôi nhớ thời đại đó và tôi đồng ý rằng các mô hình thiếu máu là kỳ quặc. Tôi đã xây dựng một ứng dụng giao dịch FX nguyên khối lớn và không có mô hình nào, thực sự, nó rất kinh khủng.

Với microservices, các dịch vụ nhỏ với hành vi phong phú của chúng, được cho là các mô hình có thể kết hợp và tổng hợp trong một miền. Vì vậy, bản thân các triển khai microservice có thể không yêu cầu thêm DDD. Ứng dụng microservice có thể là miền.

Một microservice đơn đặt hàng có thể có rất ít chức năng, được thể hiện dưới dạng tài nguyên RESTful hoặc thông qua SOAP hoặc bất cứ thứ gì. Mã microservice của đơn đặt hàng có thể cực kỳ đơn giản.

Một dịch vụ đơn lẻ (vi mô) lớn hơn, đặc biệt là một dịch vụ giữ mô hình trong RAM, có thể được hưởng lợi từ DDD.


Bạn có bất kỳ ví dụ mã nào cho các dịch vụ vi mô HTTP đại diện cho tình trạng hiện tại của bạn không? Không yêu cầu bạn viết bất cứ điều gì, chỉ cần chia sẻ liên kết nếu bạn có bất cứ điều gì bạn có thể chỉ ra. Cảm ơn.
Casey Plummer

7

Một trong những lợi ích của các lớp tên miền phong phú là bạn có thể gọi hành vi (phương thức) của chúng mỗi khi bạn có tham chiếu đến đối tượng trong bất kỳ lớp nào. Ngoài ra, bạn có xu hướng viết các phương pháp nhỏ và phân tán để cộng tác với nhau. Trong các lớp miền thiếu máu, bạn có xu hướng viết các phương thức thủ tục béo (trong lớp dịch vụ) thường được điều khiển bởi trường hợp sử dụng. Chúng thường ít bảo trì hơn so với các lớp miền phong phú.

Một ví dụ về các lớp miền có các hành vi:

class Order {

     String number

     List<OrderItem> items

     ItemList bonus

     Delivery delivery

     void addItem(Item item) { // add bonus if necessary }

     ItemList needToDeliver() { // items + bonus }

     void deliver() {
         delivery = new Delivery()
         delivery.items = needToDeliver()
     }

}

Phương thức needToDeliver()sẽ trả về danh sách các mặt hàng cần được giao bao gồm cả tiền thưởng. Nó có thể được gọi bên trong lớp, từ một lớp liên quan khác hoặc từ một lớp khác. Ví dụ, nếu bạn vượt qua Orderđể xem, thì bạn có thể sử dụng danh sách needToDeliver()đã chọn Orderđể hiển thị các mục cần được xác nhận bởi người dùng trước khi họ nhấp vào nút lưu để duy trì Order.

Trả lời bình luận

Đây là cách tôi sử dụng lớp miền từ bộ điều khiển:

def save = {
   Order order = new Order()
   order.addItem(new Item())
   order.addItem(new Item())
   repository.create(order)
}

Việc tạo ra Ordervà của nó LineItemlà trong một giao dịch. Nếu LineItemkhông thể tạo một trong các mục không thể tạo, Ordersẽ không tạo.

Tôi có xu hướng có phương pháp đại diện cho một giao dịch duy nhất, chẳng hạn như:

def deliver = {
   Order order = repository.findOrderByNumber('ORDER-1')
   order.deliver()       
   // save order if necessary
}

Bất cứ thứ gì bên trong deliver() sẽ được thực hiện như một giao dịch duy nhất. Nếu tôi cần thực thi nhiều phương thức không liên quan trong một giao dịch, tôi sẽ tạo một lớp dịch vụ.

Để tránh ngoại lệ tải chậm, tôi sử dụng biểu đồ thực thể có tên JPA 2.1. Ví dụ: trong bộ điều khiển cho màn hình phân phối, tôi có thể tạo phương thức để tải deliverythuộc tính và bỏ qua bonus, chẳng hạn như repository.findOrderByNumberFetchDelivery(). Trong màn hình thưởng, tôi gọi một phương thức khác tải bonusthuộc tính và bỏ qua delivery, chẳng hạn như repository.findOrderByNumberFetchBonus(). Điều này đòi hỏi kỷ luật vì tôi vẫn không thể gọi deliver()bên trong màn hình tiền thưởng.


1
Làm thế nào về phạm vi giao dịch?
kboom

5
Các hành vi của mô hình miền không được chứa logic liên tục (bao gồm cả giao dịch). Chúng phải có thể kiểm tra được (trong kiểm thử đơn vị) mà không cần kết nối với cơ sở dữ liệu. Phạm vi giao dịch là trách nhiệm của lớp dịch vụ hoặc lớp bền vững.
jocki

1
Làm thế nào về lười tải sau đó?
kboom,

Khi bạn tạo các phiên bản lớp miền trong thử nghiệm đơn vị, chúng không ở trạng thái được quản lý vì chúng là các đối tượng thuần túy. Tất cả các hành vi có thể được kiểm tra đúng cách.
jocki

Và điều gì sẽ xảy ra khi bạn đang mong đợi đối tượng miền từ lớp dịch vụ? Nó không được quản lý sau đó?
kboom,

2

Tôi nghĩ rằng gốc rễ của vấn đề là ở sự phân đôi sai lầm. Làm thế nào để có thể trích xuất 2 mô hình này: giàu và "thiếu máu" và để đối chiếu chúng với nhau? Tôi nghĩ chỉ có thể xảy ra nếu bạn có ý tưởng sai lầm về lớp học là gì . Tôi không chắc, nhưng tôi nghĩ tôi đã tìm thấy nó trong một trong những video của Bozhidar Bozhanov trên Youtube. Một lớp không phải là một dữ liệu + các phương thức trên dữ liệu này. Đó là cách hiểu hoàn toàn không hợp lệ dẫn đến việc phân chia các lớp thành hai loại: chỉ dữ liệu, mô hình thiếu máudữ liệu + phương thức - mô hình quá phong phú (nói đúng hơn là có loại thứ 3: chỉ các phương thức chẵn).

Sự thật là lớp là một khái niệm trong một mô hình bản thể học nào đó, một từ, một định nghĩa, một thuật ngữ, một ý tưởng, nó là một DENOTAT . Và sự hiểu biết này giúp loại bỏ sự phân đôi sai lầm: bạn không thể có CHỈ có mô hình thiếu máu hoặc CHỈ có mô hình phong phú, bởi vì điều đó có nghĩa là mô hình của bạn không đầy đủ, không phù hợp với thực tế: một số khái niệm chỉ có dữ liệu, một số khái niệm chỉ có phương pháp, một số trong số chúng là hỗn hợp. Bởi vì chúng tôi cố gắng mô tả, trong trường hợp này, một số danh mục, tập đối tượng, quan hệ, khái niệm với các lớp và như chúng ta đã biết, một số khái niệm chỉ là quy trình (phương thức), một số trong số chúng chỉ là tập thuộc tính (dữ liệu), một số chúng là quan hệ với các thuộc tính (hỗn hợp).

Tôi nghĩ rằng một ứng dụng thích hợp nên bao gồm tất cả các loại lớp và tránh để chỉ giới hạn một cách cuồng tín cho một mô hình. Dù sao đi nữa, logic biểu diễn như thế nào: với mã hoặc với các đối tượng dữ liệu có thể diễn giải được (như Free Monads ), chúng ta nên có các lớp (khái niệm, biểu tượng) đại diện cho các quy trình, logic, quan hệ, thuộc tính, tính năng, dữ liệu, v.v. và không để cố gắng tránh một số trong số chúng hoặc giảm tất cả chúng thành một loại duy nhất.

Vì vậy, chúng ta có thể trích xuất logic sang một lớp khác và để lại dữ liệu trong lớp ban đầu, nhưng điều đó không hợp lý vì một số khái niệm có thể bao gồm các thuộc tính và quan hệ / quy trình / phương thức và việc tách chúng sẽ trùng lặp khái niệm dưới 2 tên có thể là giảm xuống các mẫu: "OBJECT-Attributes" và "OBJECT-Logic". Ngôn ngữ thủ tục và chức năng là tốt vì giới hạn của chúng nhưng đó là sự tự kiềm chế quá mức đối với một ngôn ngữ cho phép bạn mô tả tất cả các loại khái niệm.


0

Mô hình miền thiếu máu rất quan trọng đối với ORM và dễ dàng truyền qua mạng (huyết mạch của tất cả các ứng dụng thương mại) nhưng OO rất quan trọng để đóng gói và đơn giản hóa các phần 'giao dịch / xử lý' trong mã của bạn.

Do đó, điều quan trọng là có thể xác định và chuyển đổi từ thế giới này sang thế giới khác.

Đặt tên cho Anemic mô hình gì đó như AnemicUser hoặc UserDAO, v.v. để các nhà phát triển biết có một lớp tốt hơn để sử dụng, sau đó có một phương thức khởi tạo thích hợp cho lớp không Anemic

User(AnemicUser au)

và phương pháp tiếp hợp để tạo lớp thiếu máu để vận chuyển / tồn tại

User::ToAnemicUser() 

Hướng đến việc sử dụng Không người dùng thiếu máu ở mọi nơi bên ngoài phương tiện vận chuyển / liên tục


-1

Đây là một ví dụ có thể giúp:

Thiếu máu

class Box
{
    public int Height { get; set; }
    public int Width { get; set; }
}

Không thiếu máu

class Box
{
    public int Height { get; private set; }
    public int Width { get; private set; }

    public Box(int height, int width)
    {
        if (height <= 0) {
            throw new ArgumentOutOfRangeException(nameof(height));
        }
        if (width <= 0) {
            throw new ArgumentOutOfRangeException(nameof(width));
        }
        Height = height;
        Width = width;
    }

    public int area()
    {
       return Height * Width;
    }
}

Điều này có vẻ như nó có thể được chuyển đổi thành ValueObject so với một Thực thể.
code5

Chỉ là một bản sao dán từ Wikipedia mà không có bất kỳ lời giải thích nào
vào

ai viết sớm hơn? @wst
Alireza Rahmani Khalili

@AlirezaRahmaniKhalili theo lịch sử Wikipedia, họ là người đầu tiên ... Trừ khi, tôi không hiểu câu hỏi của bạn.
'19

-1

Cách tiếp cận cổ điển đối với DDD không chỉ ra rằng phải tránh Mô hình Anemic vs Rich bằng mọi giá. Tuy nhiên, MDA vẫn có thể áp dụng tất cả các khái niệm DDD (bối cảnh bị ràng buộc, bản đồ ngữ cảnh, đối tượng giá trị, v.v.) nhưng sử dụng mô hình Anemic vs Rich trong mọi trường hợp. Có nhiều trường hợp việc sử dụng Dịch vụ miền để sắp xếp các Trường hợp sử dụng miền phức tạp trên một tập hợp các miền tổng hợp là một cách tiếp cận tốt hơn nhiều so với chỉ các tổng hợp được gọi từ lớp ứng dụng. Sự khác biệt duy nhất so với phương pháp DDD cổ điển là tất cả các xác nhận và quy tắc kinh doanh nằm ở đâu? Có một cấu trúc mới được gọi là trình xác nhận mô hình. Trình xác thực đảm bảo tính toàn vẹn của mô hình đầu vào đầy đủ trước khi bất kỳ trường hợp sử dụng hoặc quy trình công việc miền nào diễn ra. Các thực thể gốc tổng hợp và thực thể con đều thiếu máu nhưng mỗi thực thể có thể có trình xác thực mô hình của riêng mình được gọi khi cần thiết, bởi trình xác nhận gốc của nó. Trình xác thực vẫn tuân thủ SRP, dễ bảo trì và có thể kiểm tra đơn vị.

Lý do cho sự thay đổi này là chúng tôi hiện đang hướng tới một API trước tiên hơn là một cách tiếp cận UX đầu tiên cho Microservices. REST đã đóng một phần rất quan trọng trong việc này. Cách tiếp cận API truyền thống (vì SOAP) ban đầu được cố định dựa trên API dựa trên lệnh so với các động từ HTTP (POST, PUT, PATCH, GET và DELETE). API dựa trên lệnh rất phù hợp với cách tiếp cận hướng đối tượng Rich Model và vẫn còn rất nhiều giá trị. Tuy nhiên, các API dựa trên CRUD đơn giản, mặc dù chúng có thể vừa với Mô hình phong phú, nhưng sẽ phù hợp hơn nhiều với các mô hình đơn giản, trình xác thực và Dịch vụ miền để sắp xếp phần còn lại.

Tôi yêu DDD ở tất cả những gì nó cung cấp nhưng có lúc bạn cần kéo giãn nó một chút để phù hợp với sự thay đổi liên tục và cách tiếp cận tốt hơn với kiến ​​trúc.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.