Tránh mô hình miền thiếu máu - một ví dụ thực tế


76

Tôi đang cố gắng hiểu Mô hình miền thiếu máu và tại sao chúng được cho là mô hình chống lại.

Đây là một ví dụ thực tế.

Tôi có một lớp Nhân viên, lớp này có rất nhiều thuộc tính - tên, giới tính, tên người dùng, v.v.

public class Employee
{
    public string Name { get; set; }
    public string Gender { get; set; }
    public string Username { get; set; }
    // Etc.. mostly getters and setters
}

Tiếp theo, chúng tôi có một hệ thống liên quan đến việc luân phiên các cuộc gọi đến và các câu hỏi về trang web (được gọi là 'khách hàng tiềm năng') đồng đều giữa các nhân viên bán hàng. Hệ thống này khá phức tạp vì nó liên quan đến các yêu cầu tổng hợp vòng tròn, kiểm tra ngày nghỉ, sở thích của nhân viên, v.v. Vì vậy, hệ thống này hiện được tách thành một dịch vụ: EmployeeLeadRotationService.

public class EmployeeLeadRotationService : IEmployeeLeadRotationService
{
     private IEmployeeRepository _employeeRepository;
     // ...plus lots of other injected repositories and services

     public void SelectEmployee(ILead lead)
     {
         // Etc. lots of complex logic
     }
}

Sau đó, ở mặt sau của biểu mẫu yêu cầu trang web của chúng tôi, chúng tôi có mã như sau:

public void SubmitForm()
{
    var lead = CreateLeadFromFormInput();

    var selectedEmployee = Kernel.Get<IEmployeeLeadRotationService>()
                                 .SelectEmployee(lead);

    Response.Write(employee.Name + " will handle your enquiry. Thanks.");
}

Tôi không thực sự gặp nhiều vấn đề với cách tiếp cận này, nhưng được cho là đây là thứ mà tôi nên chạy vì nó là Mô hình miền thiếu máu .

Nhưng đối với tôi, nó không rõ ràng là logic trong dịch vụ luân chuyển khách hàng tiềm năng sẽ đi đến đâu. Nó có nên đi đầu không? Nó có nên đi vào nhân viên không?

Còn về tất cả các kho lưu trữ được đưa vào, v.v. mà dịch vụ luân chuyển yêu cầu - chúng sẽ được đưa vào nhân viên như thế nào, vì hầu hết thời gian khi giao dịch với nhân viên chúng ta không cần bất kỳ kho lưu trữ nào trong số này?


Vì vậy, một ILeadcái nhìn như thế nào, nếu nó không rõ ràng để đặt .SelectEFastee () trong đó?
Simon Buchan

Chà, dẫn đầu trong trường hợp này là một cuộc điều tra trên web, vì vậy nó sẽ có thuộc tính Nhận xét, v.v. Nhưng chúng tôi cũng có các câu hỏi qua điện thoại, ứng dụng, báo giá, v.v. tất cả đều hơi khác một chút. Giao diện ILead sẽ có các thuộc tính như LocationOfLead, TimeOfLead, v.v.
cbp

1
Vì vậy, tôi đoán sẽ rõ ràng hơn nếu đặt .SelectErantyee () vào vị trí dẫn đầu hơn là nhân viên, nhưng điều đó không giải quyết được các mối quan tâm khác: việc đưa vào các kho lưu trữ phụ thuộc; việc thiếu SoC; mức độ phức tạp tổng thể của việc có tất cả mã SelectE Employee này trong lớp Khách hàng tiềm năng (thực sự chúng ta sẽ cần một lớp LeadBase để chúng ta không sử dụng lại mã trên tất cả các lớp khách hàng tiềm năng kế thừa) khi rất nhiều thời gian (ví dụ: trong khi báo cáo) chúng ta thực sự không quan tâm đến việc nhân viên được chọn như thế nào.
cbp

Có thể là một số lợi ích: medium.com/@wrong.about/...
Vadim Samokhin

Câu trả lời:


55

Trong trường hợp này, điều này không cấu thành Mô hình miền thiếu máu. Mô hình miền Anemic đặc biệt về xác thực và chuyển đổi các đối tượng . Vì vậy, một ví dụ về điều này sẽ là nếu một chức năng bên ngoài thực sự thay đổi trạng thái của Nhân viên hoặc cập nhật chi tiết của họ.

những gì đang xảy ra trong trường hợp này là bạn đang lấy tất cả nhân viên và lựa chọn một trong số họ dựa trên thông tin của họ. Sẽ tốt hơn nếu có một đối tượng riêng biệt để kiểm tra những người khác và đưa ra quyết định về những gì nó tìm thấy. KHÔNG ĐƯỢC nếu có một đối tượng được sử dụng để chuyển một đối tượng từ trạng thái này sang trạng thái khác.

Ví dụ về Mô hình miền Anemic trong trường hợp của bạn là có một phương thức bên ngoài

updateHours(Employee emp) // updates the working hours for the employee

lấy một đối tượng Nhân viên và cập nhật số giờ làm việc của nó trong tuần, đảm bảo rằng cờ sẽ được nâng lên nếu số giờ vượt quá một giới hạn nhất định. Vấn đề với điều này là nếu bạn chỉ có đối tượng Nhân viên thì bạn không có kiến ​​thức về cách sửa đổi giờ của họ trong các ràng buộc chính xác. Trong trường hợp này, cách xử lý sẽ là di chuyển phương thức updateHours vào lớp Employee. Đó là mấu chốt của mô hình chống Mô hình miền thiếu máu.


Nhưng điều gì sẽ xảy ra nếu Nhân viên là Đối tượng Cố định cho cơ sở dữ liệu. Tại sao tôi nên đặt một phương pháp vào đó? Câu hỏi tương tự cũng hợp lệ cho DTO`s mà bạn không đặt các phương thức bên trong. Sau đó, bạn sẽ đặt phương thức updateHours ở đâu?
Pascal

updateHoursthuộc về lớp Nhân viên. Bạn nên chuyển cho nó bất kỳ dữ liệu nào cần thiết để cập nhật giờ, ví dụ như nhiệm vụ đã được hoàn thành. Đối tượng cộng tác viên cũng được, nhưng tốt nhất là không có dịch vụ.
MauganRa

30

Tôi nghĩ rằng thiết kế của bạn là tốt ở đây. Như bạn đã biết, mô hình chống mô hình miền thiếu máu là một phản ứng dữ dội chống lại xu hướng tránh bất kỳ hành vi nào được mã hóa trong các đối tượng miền. Nhưng ngược lại, nó không có nghĩa là tất cả các hành vi liên quan đến một đối tượng miền phải được đóng gói bởi đối tượng đó.

Như một quy tắc chung, hành vi được liên kết nội tại với đối tượng miền và được xác định hoàn toàn theo nghĩa là một cá thể đối tượng miền có thể được đưa vào đối tượng miền. Nếu không, để đảm bảo trách nhiệm rõ ràng, tốt nhất bạn nên đặt nó ra bên ngoài trong một cộng tác viên / dịch vụ như bạn đã làm.


5
chính xác. Đó là realyl một mô-đun bên ngoài (LeadQueueManager hoặc bất cứ thứ gì) với rất nhiều logic bên trong - đây hoàn toàn không phải là một mô hình miền thiếu máu. Nhân viên biết gì về lập lịch hàng đợi cuộc gọi? Không có gì;)
TomTom

14

Đó là tất cả trong đầu của bạn - hãy coi dịch vụ xoay vòng là một phần của mô hình miền và vấn đề sẽ tan biến.

Luân chuyển cần lưu giữ thông tin về nhiều nhân viên, vì vậy nó không thuộc về khách hàng tiềm năng, cũng không thuộc về bất kỳ đối tượng nhân viên nào. Bản thân nó xứng đáng là một đối tượng miền.

Chỉ cần đổi tên "RotationService" thành một cái gì đó như "Organization.UserSupportDepartment" là có thể thấy rõ.


0

Nếu mô hình miền của bạn chỉ chứa các vai trò và sự vật, không chứa các hoạt động dưới dạng hành vi, thì mô hình đó là thiếu máu. Tuy nhiên, tôi đang nói về hành vi liên quan đến một mô hình không phải là một đối tượng . Tôi nói về sự khác biệt giữa chúng trong một câu trả lời khác ... https://stackoverflow.com/a/31780937/116442

Từ câu hỏi của bạn, bạn vi phạm hai quy tắc lập mô hình phân tích tên miền đầu tiên của tôi: -

  1. Hành vi được mô hình hóa dưới dạng (được ghi lại) Các hoạt động là trọng tâm của mô hình miền. Thêm chúng trước.
  2. Mô hình hóa các hoạt động miền dưới dạng Lớp, không phải phương thức.

Tôi sẽ thêm một hoạt động "Yêu cầu" vào mô hình. Với nó, mô hình có hành vi và có thể kết hợp và hoạt động như một nhóm các đối tượng mà không cần bộ điều khiển bên ngoài hoặc tập lệnh.

EnquiryHandlerModel

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.