2012-01-17 29 views
9

Thông thường khi tôi cần tiêm một hoặc nhiều dịch vụ vào một dịch vụ khác, tôi tiêm một cách rõ ràng mỗi dịch vụ. Tuy nhiên, tôi có một tình huống mà việc tự tiêm chích dịch vụ sẽ thực sự làm mọi thứ dễ dàng hơn. Tôi biết đây không phải là một thực hành được đề nghị, nhưng tôi tò mò những lý do kỹ thuật là gì để ngăn cản điều này. Nó có phải là một cái gì đó hợp pháp như nó quá mã nguồn lực, hoặc một cảm giác cá nhân hơn rằng nó quá lộn xộn?Những lý do kỹ thuật nào để tránh tiêm chích chứa dịch vụ thay vì các dịch vụ cá nhân?

Trả lời

13

Nếu bạn tiêm bình chứa, bạn không làm cho phụ thuộc rõ ràng. Trong thực tế, bạn đang che khuất chúng nhiều hơn trước. Nếu bạn có một lớp học như thế này ...

class DocumentCreator(IFileNamer fileNamer, IRepository repository) 
{ ... } 

... bạn có thể xem phụ thuộc là gì. Bạn cũng có thể dễ dàng giả lập các phụ thuộc đó để kiểm thử đơn vị, để đảm bảo rằng bạn tách biệt DocumentCreator và có thể biết rằng bất kỳ lỗi thử nghiệm nào là kết quả của mã của nó chứ không phải là mã trong một trong các phụ thuộc của nó.

Nếu, mặt khác, bạn làm điều này ...

class DocumentCreator(IDependencyContainer container) 
{ ... } 

... bạn đã che khuất sự phụ thuộc. Bạn không thể biết, mà không kiểm tra nội bộ của lớp, rằng nó đòi hỏi một IFileNamer và một IRepository.

Bạn cũng không thể dễ dàng biết được những gì bạn cần đặt trong thùng chứa để kiểm tra DocumentCreator. Giả mạo IDependencyContainer sẽ không giúp bạn chút nào; lớp của bạn sẽ vẫn không thành công khi thử nghiệm vì vùng chứa sẽ không chứa IFileNamer và IRepository, trừ khi bạn kiểm tra các lớp bên trong của lớp để thấy rằng chúng được yêu cầu.

4

Tôi nghĩ rằng vấn đề chính với cách tiếp cận này là bạn không thấy phụ thuộc rõ ràng nữa. Một vấn đề khác có thể là khó kiểm tra hơn.

+0

Tôi chắc chắn đồng ý với phần đầu tiên, và đó là lý do tại sao ngoại trừ những trường hợp hiếm hoi mà tôi vẫn tiếp tục tiêm các dịch vụ cụ thể. Nhưng tôi không chắc làm thế nào thử nghiệm nó sẽ khó khăn hơn? –

+1

Nó sẽ ngụ ý tạo đối tượng vùng chứa và tiêm các dịch vụ giả lập (hoặc không được mô phỏng) vào nó, thay vì tiêm chúng trực tiếp, tạo thêm một bước nữa. – greg0ire

+0

Hmm, đó chắc chắn là một bất lợi lớn. –

3

Những gì bạn mô tả là ServiceLocator. Đây được coi là một mô hình chống trong thiết kế ứng dụng hiện đại. This article mô tả lý do.

+0

Sai. Mọi người thực sự cần phải ngừng liên kết với blog của anh chàng đó. Đây là cái nhìn sâu sắc từ một bậc thầy có kỹ năng hơn. http://www.martinfowler.com/articles/injection.html – Colin

+1

@Colin Bạn đã bao giờ đọc lý do Mark Seemann tuyên bố ServiceLocator là một mô hình chống lại? Bạn chỉ đạt được một vài lợi thế của việc tiêm phụ thuộc đầy đủ nhưng bỏ lỡ một vài lợi ích (tức là khả năng hiển thị tức thì của các phụ thuộc). Tôi bổ sung SL vi phạm các quy tắc khác nhau về thiết kế phần mềm như gói gọn http://blog.ploeh.dk/2015/10/26/service-locator-violates-encapsulation/ hoặc SOLID http://blog.ploeh.dk/2014/05/15/service-locator-violates-solid/ –

+0

Có, và nó là vô nghĩa. Trong thực tế, đối lập của lập luận của ông là đúng sự thật. Ví dụ, anh ta nói nó "đóng gói chiến dịch", nhưng toàn bộ điểm đóng gói là che giấu các chi tiết bên trong của lớp mà người gọi không nên quan tâm (như xác thực, mà anh ta bên ngoài trong ví dụ của mình). DI có các ứng dụng và lợi ích rõ ràng nhưng nó không phải là "búa vàng"; Đó là một mô hình chống. Hãy suy nghĩ nếu bạn phải vượt qua TraceListeners mỗi khi bạn gọi Trace.WriteLine() hoặc Debug.WriteLine()! Tôi ước mọi người sẽ dừng việc đối xử với ông Seeman như một chuyên gia; anh ấy chỉ là một blogger được đánh giá cao. – Colin

Các vấn đề liên quan