2008-10-01 25 views
15

Tôi đã thêm tính năng tiêm phụ thuộc vào mã của tôi vì nó làm cho mã dễ dàng hơn nhiều để kiểm tra Đơn vị thông qua chế nhạo.Việc tiêm phụ thuộc có phá vỡ Luật Demeter hay không

Tuy nhiên, tôi yêu cầu các đối tượng cao hơn chuỗi cuộc gọi của tôi để có kiến ​​thức về các đối tượng tiếp tục xuống chuỗi cuộc gọi.

Điều này có vi phạm Luật Demeter không? Nếu nó có vấn đề gì?

ví dụ: lớp A có sự phụ thuộc vào giao diện B, việc triển khai giao diện này để sử dụng được tiêm vào hàm tạo của lớp A. Bất kỳ ai muốn sử dụng lớp A cũng phải có tham chiếu đến việc triển khai B. Và có thể gọi phương thức của nó trực tiếp có ý nghĩa và có kiến ​​thức về các thành phần phụ của nó (giao diện B)

Wikipedia nói về định luật Demeter: "Khái niệm cơ bản là một đối tượng nhất định nên giả định càng ít càng tốt về cấu trúc hoặc thuộc tính của bất kỳ thứ gì khác (bao gồm cả các thành phần con của nó). "

+1

Bạn có thể đăng một số mã mẫu không? Nếu bạn đang làm foo.bar(). Baz() thì có, bạn đang vi phạm Luật Demeter. Bạn đang nói rằng bạn sẽ làm điều này? – asterite

Trả lời

11

Tiêm phụ thuộc CÓ THỂ vi phạm Luật Demeter. Nếu bạn buộc người tiêu dùng phải tiêm các phụ thuộc. Điều này có thể tránh được thông qua các phương pháp nhà máy tĩnh và các khuôn khổ DI.

Bạn có thể có cả hai bằng cách thiết kế đối tượng theo cách mà chúng yêu cầu phụ thuộc được truyền vào và đồng thời có cơ chế sử dụng chúng mà không thực hiện thao tác tiêm (chức năng nhà máy và khung DI).

+0

Tôi nghĩ bạn đã đóng đinh nó. Một số câu trả lời khác cho câu hỏi này không tập trung vào tình hình cụ thể của người hỏi. – moffdub

+0

Bạn có thể xây dựng trên thuật ngữ 'người tiêu dùng' không? – meowsqueak

+0

Trong trường hợp này, người tiêu dùng của một Lớp là bất kỳ mã nào khác gọi các phương thức trên lớp đó. –

1

Luật có vi phạm không?
Nói đúng, tôi nghĩ là vậy.
Có quan trọng không?
Mối nguy hiểm chính của việc vi phạm pháp luật là bạn làm cho mã của bạn trở nên dễ vỡ hơn.
Nếu bạn thực sự giữ nó chỉ là các bài kiểm tra, có vẻ như nguy hiểm đó không quá tệ.
Giảm nhẹ
Sự hiểu biết của tôi về Law of Demeter là nó có thể được theo sau bởi có "phương pháp bao bọc" ngăn chặn việc gọi trực tiếp vào đối tượng.

3

Làm cách nào để phá vỡ nó? DI hoàn toàn phù hợp với ý tưởng về kiến ​​thức ít nhất. DI cung cấp cho bạn khớp nối thấp - các đối tượng ít bị đơn trên mỗi khác.

Trích dẫn Wikipedia:

... một đối tượng A có thể yêu cầu dịch vụ (gọi một phương pháp) của một đối tượng dụ B, nhưng đối tượng A không thể “đạt được thông qua” đối tượng B để truy cập được nêu ra đối tượng khác ...

Thông thường DI hoạt động giống hệt như cách bạn sử dụng dịch vụ được cung cấp bởi các thành phần được tiêm. Nếu đối tượng của bạn cố gắng truy cập một số phụ thuộc của B tức là nó biết nhiều về B - đó là dẫn đến khớp nối cao và phá vỡ ý tưởng của DI

Tuy nhiên tôi đang yêu cầu đối tượng cao hơn lên chuỗi cuộc gọi của tôi để có kiến ​​thức về các đối tượng tiếp tục xuống chuỗi cuộc gọi

Một số ví dụ?

2

Nếu tôi hiểu bạn một cách chính xác, điều này không phải do việc sử dụng tiêm phụ thuộc, điều này là do sử dụng các chiến lược nhạo báng mà bạn chỉ định hàm gọi bạn mong đợi một phương thức tạo. Điều đó hoàn toàn có thể chấp nhận được trong nhiều tình huống, nhưng rõ ràng điều đó có nghĩa là bạn phải biết điều gì đó về phương pháp bạn đang gọi, nếu bạn đã chỉ định những gì bạn nghĩ rằng nó phải làm.

Viết phần mềm tốt yêu cầu cân bằng cân bằng.Khi việc triển khai trở nên hoàn chỉnh hơn, nó trở nên không nhất quán. Bạn phải quyết định những rủi ro mà những mâu thuẫn đó tạo ra, và liệu chúng có đáng giá trị do sự hiện diện của chúng tạo ra hay không.

1

Luật Demeter quy định rằng phương pháp M của đối tượng O có thể gọi các phương thức trên các đối tượng được tạo/khởi tạo bên trong M. Tuy nhiên, không có gì xác định cách các đối tượng này được tạo ra. Tôi nghĩ rằng nó hoàn toàn tốt đẹp khi sử dụng một đối tượng trung gian để tạo ra chúng, miễn là mục đích của đối tượng đó trong cuộc sống chỉ là vậy - tạo ra các vật thể khác thay cho bạn. Theo nghĩa này, DI không phá luật Demeter.

0

Phụ thuộc :-)

Tôi nghĩ câu trả lời đầu là không đúng, ngay cả với một khuôn khổ rất nhiều mã sử dụng tiêm phụ thuộc và tiêm nhiễm đối tượng cao cấp. Sau đó bạn nhận được mã spaghetti với rất nhiều phụ thuộc.

Tiêm phụ thuộc được sử dụng tốt nhất cho tất cả những thứ có thể làm ô nhiễm mô hình đối tượng của bạn, ví dụ như một ILogger. Nếu bạn tiêm đối tượng kinh doanh đảm bảo nó ở mức thấp nhất có thể và cố gắng truyền nó theo phương pháp truyền thống nếu bạn có thể. Chỉ sử dụng tiêm phụ thuộc nếu nó bị lộn xộn.

0

Trước khi thêm câu trả lời, tôi phải đủ điều kiện. Lập trình hướng dịch vụ được xây dựng dựa trên các nguyên tắc OOP và sử dụng các ngôn ngữ OO. Ngoài ra, SOA tuân theo Nguyên tắc Kiểm soát và Nguyên tắc RẮN đối với răng. Vì vậy, rất nhiều lập trình viên hướng dịch vụ chắc chắn sẽ đến đây. Vì vậy, câu trả lời này là dành cho các lập trình viên hướng dịch vụ đến với câu hỏi này, bởi vì SOA được xây dựng trên OOP. Điều này không trực tiếp trả lời ví dụ của OP, nhưng trả lời câu hỏi từ một Phối cảnh SOA.

Nói chung, Luật Demeter không áp dụng cho Kiến trúc hướng dịch vụ. Đối với OO, Luật Demeter đang nói về "Rich Objects" trong OOP có các thuộc tính và phương thức, và thuộc tính của nó cũng có thể có các phương thức. Với các mô hình OOP Rich, có thể tiếp cận thông qua một chuỗi các đối tượng và các phương thức truy cập, các thuộc tính, các phương thức của các thuộc tính, các phương thức của các đặc tính của thuộc tính,… Nhưng trong Lập trình hướng dịch vụ, Dữ liệu (Properties) được tách ra khỏi Process (Methods)). Mô hình của bạn (chủ yếu) chỉ có các thuộc tính (Chắc chắn không bao giờ phụ thuộc) và Dịch vụ của bạn chỉ có Phương thức và phụ thuộc trên các Dịch vụ khác.

Trong SOP, bạn có thể tự do xem lại các thuộc tính của mô hình và các thuộc tính của thuộc tính của mô hình đó. Bạn sẽ không bao giờ có thể truy cập các phương thức bạn không nên, chỉ có một cây dữ liệu. Nhưng còn về Dịch vụ thì sao? Luật Demeter có áp dụng ở đó không?

Có, Luật Demeter Có thể là áp dụng cho Dịch vụ SOP. Nhưng một lần nữa, luật ban đầu được thiết kế cho Mô hình phong phú trong OOP. Và mặc dù pháp luật Có thể được áp dụng cho các dịch vụ cho Dịch vụ, nhưng việc áp dụng Dependency Injection tự động hoàn thành Luật Demeter. Theo nghĩa đó, DI không thể phá luật.

Trong sự đối lập hạn chế với Mark Roddy, tôi không thể tìm thấy bất kỳ tình huống nào bạn có thể nói hợp pháp về Dependency Injection và "consumer" trong cùng một câu. Nếu bởi "người tiêu dùng" bạn có nghĩa là một lớp học đang tiêu thụ một lớp khác, điều đó không có ý nghĩa.Với DI, bạn sẽ có một Root Root sáng tác đồ thị đối tượng của bạn, và một lớp không bao giờ nên biết một lớp khác thậm chí tồn tại. Nếu bởi "người tiêu dùng" bạn có nghĩa là một lập trình viên, thì làm thế nào họ không bị buộc phải "làm tiêm." Lập trình viên là người đã tạo ra Root Root, vì vậy họ phải thực hiện việc tiêm. Một lập trình viên không bao giờ nên "làm tiêm" như là một instantiation trong một lớp học để tiêu thụ một lớp học.

Vui lòng xem ví dụ sau đây cho thấy các giải pháp thực tế riêng biệt, tài liệu tham khảo của họ, và mã thực hiện: "Core"

In SOA, DI doesn't allow breaking of LoD

Ở phía trên bên phải, chúng ta có Rất nhiều gói trên NuGet và NPM có một dự án "Core" có Mô hình, Giao diện và thậm chí có thể triển khai mặc định. Lõi không bao giờ nên phụ thuộc vào bất cứ điều gì bên ngoài.

Ở trên cùng bên trái, chúng tôi có triển khai lõi bên ngoài. Việc thực hiện phụ thuộc vào Core, và do đó có kiến ​​thức về nó.

Ở dưới cùng bên trái, chúng tôi có một tên miền độc lập. Miền có sự phụ thuộc vào một số triển khai lõi, nhưng Không cần biết về việc triển khai.

Đây là nơi tôi chỉ ra rằng cả Miền và Triển khai đều không biết nhau tồn tại. Có một cơ hội 0% hoặc có thể tiếp cận (hoặc hơn thế nữa) cái kia, bởi vì họ thậm chí không biết chúng tồn tại. Tên miền chỉ biết rằng có một hợp đồng, và bằng cách nào đó nó có thể tiêu thụ các phương thức bằng bất cứ thứ gì được tiêm vào nó.

Ở phía dưới cùng bên trái là Root Root hoặc Entry-Point. Điều này còn được gọi là "Ranh giới phía trước" của ứng dụng. Thư mục gốc của một ứng dụng biết tất cả các thành phần của nó và làm nhiều hơn là lấy đầu vào, xác định ai để gọi, soạn các đối tượng và trả về các kết quả đầu ra. Nói cách khác, nó chỉ có thể nói cho Tên miền "Ở đây, hãy sử dụng điều này để hoàn thành hợp đồng của bạn cho ICalculateThings, sau đó cho tôi kết quả của CalculateTwoThings.

Thực sự là một cách để đập vỡ mọi thứ vào cùng một dự án, Dịch vụ, làm cho các thuộc tính công cộng phụ thuộc của bạn thay vì các trường riêng, STILL Do Dependency-Injection (khủng khiếp), và sau đó có các dịch vụ gọi vào các phụ thuộc của các phụ thuộc. Nhưng điều đó sẽ rất tệ, nhưng bạn sẽ phải cố gắng Điều này có thể tồn tại trong một giải pháp (miễn là Kiến trúc sư kiểm soát Kiến trúc Tham khảo) và có thể có thêm một vài cách đơn giản hơn. Nhưng sự tách biệt trong hình ảnh thực sự cho thấy ho w ít kiến ​​thức hệ thống phải có về các bộ phận của nó. Chỉ có Root Root (Entry Point, Front-Boundary) cần biết về các phần.

Kết luận (TL; DR;): Trong Oldskewl OOP, Mô hình phong phú và Luật Demeter có thể dễ dàng bị phá vỡ bằng cách xem xét các mô hình mô hình để truy cập các phương pháp của chúng. Nhưng trong Newskewl SOP (được xây dựng dựa trên Nguyên tắc và Ngôn ngữ OOP), Dữ liệu được tách ra khỏi Quy trình. Vì vậy, bạn có thể cảm thấy tự do để xem xét các đặc tính của mô hình. Sau đó, đối với Dịch vụ, các phụ thuộc luôn là riêng tư và không có gì biết rằng bất kỳ điều gì khác tồn tại khác với những gì chúng được kể bởi trừu tượng, hợp đồng, giao diện.

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