Tại sao không sử dụng vùng chứa IoC để giải quyết các phụ thuộc cho các thực thể / đối tượng nghiệp vụ?


82

Tôi hiểu khái niệm đằng sau DI, nhưng tôi chỉ đang tìm hiểu những gì các vùng chứa IoC khác nhau có thể làm. Có vẻ như hầu hết mọi người ủng hộ việc sử dụng IoC container để kết nối các dịch vụ không trạng thái, nhưng còn việc sử dụng chúng cho các đối tượng trạng thái như thực thể thì sao?

Cho dù đó là đúng hay sai, tôi thường nhồi nhét các thực thể của mình với hành vi, ngay cả khi hành vi đó yêu cầu một lớp bên ngoài. Thí dụ:

public class Order : IOrder
{

    private string _ShipAddress;
    private IShipQuoter _ShipQuoter;

    public Order(IOrderData OrderData, IShipQuoter ShipQuoter)
    {
        // OrderData comes from a repository and has the data needed 
        // to construct order
        _ShipAddress = OrderData.ShipAddress;  // etc.
        _ShipQuoter = ShipQuoter;

    }

    private decimal GetShippingRate()
    {
        return _ShipQuoter.GetRate(this);
    }
}

Như bạn có thể thấy, các phụ thuộc là Constructor Injected. Bây giờ cho một vài câu hỏi.

  1. Việc để các thực thể của bạn phụ thuộc vào các lớp bên ngoài như ShipQuoter có bị coi là hành vi xấu không? Loại bỏ những phụ thuộc này dường như đưa tôi đến một miền thiếu máu, nếu tôi hiểu đúng định nghĩa.

  2. Việc sử dụng vùng chứa IoC để giải quyết những phụ thuộc này và xây dựng một thực thể khi cần thiết có phải là một phương pháp không tốt? có khả năng làm cái này không?

Cảm ơn cho bất kỳ cái nhìn sâu sắc.


3
chỉ làm công cụ mà bạn cần phải bởi vì nó làm cho công việc của bạn dễ dàng hơn, không phải vì lẽ đây là cách bạn nên làm điều đó
Omu

28
Là một lập trình viên tự học, tôi đã đi theo con đường đó, và nó dẫn đến phần mềm hiện đang được công ty tôi sử dụng. Phần mềm dựa trên tập lệnh thủ tục / giao dịch là thứ nổi lên, một phần vì nó dễ nhất và một phần vì tôi không biết cách nào tốt hơn. Việc duy trì và mở rộng là hoàn toàn khó khăn, đó là lý do tại sao tôi dành thời gian để viết lại nó và tìm kiếm lời khuyên từ những người đã khắc phục những vấn đề này về cách không mắc phải những sai lầm tương tự.
Casey Wilkins

Câu trả lời:


90

Câu hỏi đầu tiên là câu hỏi khó trả lời nhất. Có phải thực tế không tốt khi để Đối tượng phụ thuộc vào các lớp bên ngoài? Đó chắc chắn không phải là điều phổ biến nhất để làm.

Ví dụ: nếu bạn đưa một Kho lưu trữ vào các Đối tượng của mình, bạn có một cách hiệu quả việc triển khai mẫu Bản ghi Hoạt động . Một số người thích mẫu này vì sự tiện lợi mà nó mang lại, trong khi những người khác (như tôi) coi nó là mùi mã hoặc phản mẫu vì nó vi phạm Nguyên tắc trách nhiệm duy nhất (SRP).

Bạn có thể lập luận rằng việc đưa các phụ thuộc khác vào các Thực thể sẽ kéo bạn theo cùng một hướng (rời khỏi SRP). Mặt khác, bạn chắc chắn đúng rằng nếu bạn không làm điều này, lực kéo sẽ hướng tới Mô hình miền thiếu máu .

Tôi đã vật lộn với tất cả những điều này trong một thời gian dài cho đến khi tôi bắt gặp bài báo (đã bị bỏ rơi) của Greg Young trên DDDD , nơi anh ấy giải thích tại sao kiến trúc n-tier / n-lớp khuôn mẫu sẽ luôn CRUDY (và do đó khá thiếu máu).

Việc chuyển trọng tâm sang mô hình hóa các đối tượng Miền dưới dạng Lệnh và Sự kiện thay vì Danh từ dường như cho phép chúng tôi xây dựng mô hình miền hướng đối tượng thích hợp.

Câu hỏi thứ hai dễ trả lời hơn. Bạn luôn có thể sử dụng một Nhà máy trừu tượng để tạo các phiên bản tại thời điểm chạy . Với Castle Windsor, bạn thậm chí có thể sử dụng Cơ sở Nhà máy Đánh máy, giúp bạn giảm bớt gánh nặng khi thực hiện các nhà máy theo cách thủ công.


Cảm ơn Mark. Tôi đã xem Typed Factory và đọc các bài viết khác của bạn về phương pháp Abstract Factory, nhưng tôi chưa bao giờ thấy bất kỳ ví dụ nào về chúng được sử dụng để giải quyết các thực thể. Điều này có phải bởi vì hầu hết mọi người thiết kế các thực thể của họ mà không có bất kỳ phụ thuộc nào ngoại trừ một kho lưu trữ? Tôi có gặp rắc rối trên đường đi nếu tôi sử dụng nghiêm ngặt một thứ gì đó như Typed Factory để giải quyết các thực thể có phụ thuộc bên ngoài của tôi không?
Casey Wilkins

Điều tôi đang cố gắng nói là nếu Đối tượng của bạn chứa các cộng tác viên khác có thể truy cập các Đối tượng khác, v.v., bạn có thể gặp phải tất cả các loại vấn đề bảo trì - chưa kể đến vi phạm SRP và các vấn đề N + 1. Đó là lý do tại sao Evans khuyên bạn nên coi mỗi Thực thể như một Gốc tổng hợp.
Mark Seemann

Trong ví dụ của tôi, ShipQuoter lấy giá vận chuyển cho một đơn hàng từ dịch vụ web (ví dụ: UPS). Bạn sẽ đặt dịch vụ này thành một Dịch vụ chấp nhận IOrder hay bạn biến nó thành một phần của đối tượng miền như Order.GetRates?
Casey Wilkins

Tôi sẽ dành rất nhiều thời gian để tìm ra cách tôi có thể tránh một lực kéo đồng bộ ngay từ đầu. Bạn càng kéo dữ liệu theo kiểu đồng bộ, chặn thì thiết kế của bạn càng trở nên giòn hơn. Đó là lý do tại sao CQRS là một sự thay thế hấp dẫn như vậy.
Mark Seemann

4
Liên kết của bạn đến bài báo của Greg đã chết. Nhưng nó vẫn có sẵn ở đây . Và có vẻ như đây là một phiên bản mới hơn.
BornToCode

1

Tôi biết đây là một bài viết cũ nhưng muốn thêm. Thực thể miền không nên tự tồn tại ngay cả khi bạn chuyển vào kho lưu trữ trừu tượng trong ctor. Lý do tôi gợi ý điều này không chỉ đơn thuần là nó vi phạm SRP, nó còn trái ngược với sự tổng hợp của DDD. Hãy để tôi giải thích, DDD phù hợp với các ứng dụng phức tạp với biểu đồ sâu vốn có, do đó, chúng tôi sử dụng gốc tổng hợp hoặc kết hợp để duy trì các thay đổi đối với "trẻ em" cơ bản, vì vậy khi chúng tôi đưa sự kiên trì vào từng trẻ, chúng tôi vi phạm mối quan hệ mà trẻ gốc tổng hợp hoặc gốc tổng hợp phải "phụ trách" vòng đời hoặc tập hợp. Tất nhiên gốc tổng hợp hoặc tổng hợp cũng không tồn tại biểu đồ riêng của nó. Một điều khác là với sự phụ thuộc của các đối tượng DDD là một đối tượng miền được tiêm vào một cách hiệu quả không có trạng thái nào cho đến khi một số sự kiện khác diễn ra để hydrat hóa trạng thái của nó. BẤT CỨ người tiêu dùng mã nào sẽ bị buộc phải khởi động hoặc thiết lập đối tượng miền trước khi họ có thể gọi hành vi kinh doanh vi phạm tính đóng gói.

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.