Khi nào KHÔNG áp dụng Nguyên tắc đảo ngược phụ thuộc?


43

Tôi hiện đang cố gắng để tìm ra RẮN. Vì vậy, Nguyên tắc đảo ngược phụ thuộc có nghĩa là bất kỳ hai lớp nào cũng nên giao tiếp qua các giao diện, không trực tiếp. Ví dụ: Nếu class Acó một phương thức, mong muốn một con trỏ tới một đối tượng có kiểu class B, thì phương thức này thực sự sẽ mong đợi một đối tượng có kiểu abstract base class of B. Điều này cũng giúp cho Mở / Đóng.

Với điều kiện tôi hiểu điều đó một cách chính xác, câu hỏi của tôi sẽ là một cách thực hành tốt để áp dụng điều này cho tất cả các tương tác của lớp hay tôi nên thử suy nghĩ theo các lớp ?

Lý do tôi hoài nghi là vì chúng tôi đang trả một số giá cho việc tuân theo nguyên tắc này. Nói, tôi cần thực hiện tính năng Z. Sau khi phân tích, tôi kết luận rằng tính năng Zbao gồm các chức năng A, BC. Tôi tạo ra một mặt tiền lớp Z, rằng, thông qua các giao diện, sử dụng các lớp học A, BC. Tôi bắt đầu mã hóa việc thực hiện và đến một lúc nào đó tôi nhận ra rằng nhiệm vụ Zthực sự bao gồm chức năng A, BD. Bây giờ tôi cần loại bỏ Cgiao diện, Cnguyên mẫu lớp và viết Dgiao diện và lớp riêng biệt . Không có giao diện, chỉ có lớp sẽ cần phải được thay thế.

Nói cách khác, để thay đổi một cái gì đó, tôi cần thay đổi 1. người gọi 2. giao diện 3. khai báo 4. việc thực hiện. Trong một con trăn cùng trực tiếp thực hiện, tôi sẽ cần phải thay đổi chỉ thực hiện.


13
Nghịch đảo phụ thuộc đơn giản là một kỹ thuật, vì vậy nó chỉ nên được áp dụng khi cần thiết ... không có giới hạn về mức độ có thể áp dụng, vì vậy nếu bạn áp dụng nó ở mọi nơi, bạn sẽ gặp phải rác: như mọi tình huống khác kỹ thuật cụ thể.
Frank Hileman

Nói một cách đơn giản, việc áp dụng một số nguyên tắc thiết kế phần mềm phụ thuộc vào việc có thể cấu trúc lại không thương tiếc khi các yêu cầu đang thay đổi. Trong số đó, phần giao diện được cho là nắm bắt tốt nhất các bất biến hợp đồng của thiết kế, trong khi mã nguồn (triển khai) dự kiến ​​sẽ chịu đựng được những thay đổi thường xuyên hơn.
rwong

@rwong Một giao diện chỉ ghi lại các bất biến hợp đồng nếu bạn sử dụng ngôn ngữ hỗ trợ các bất biến hợp đồng. Trong các ngôn ngữ phổ biến (Java, C #), giao diện chỉ đơn giản là một bộ chữ ký API. Thêm giao diện không cần thiết chỉ làm giảm thiết kế.
Frank Hileman

Tôi sẽ nói bạn hiểu nó sai. DIP là về việc tránh phụ thuộc thời gian biên dịch từ thành phần "cấp cao" sang thành phần "cấp thấp", để cho phép tái sử dụng thành phần cấp cao trong các bối cảnh khác, trong đó bạn sẽ sử dụng triển khai khác cho mức thấp thành phần -level; điều này được thực hiện bằng cách tạo ra một kiểu trừu tượng ở cấp độ cao, được thực hiện bởi các thành phần cấp thấp; vì vậy cả hai thành phần cấp cao và cấp thấp đều phụ thuộc vào sự trừu tượng này. Cuối cùng, các thành phần cấp cao và cấp thấp giao tiếp qua một giao diện, nhưng đây không phải là bản chất của DIP.
Rogério

Câu trả lời:


87

Trong nhiều phim hoạt hình hoặc phương tiện truyền thông khác, các thế lực thiện và ác thường được minh họa bởi một thiên thần và một con quỷ ngồi trên vai của nhân vật. Trong câu chuyện của chúng tôi ở đây, thay vì thiện và ác, chúng tôi có RẮN trên một vai và YAGNI (Bạn sẽ không cần nó!) Ngồi bên kia.

Các nguyên tắc RẮN được thực hiện ở mức tối đa là phù hợp nhất cho các hệ thống enterprisey khổng lồ, phức tạp, có thể cấu hình được. Đối với các hệ thống nhỏ hơn hoặc cụ thể hơn, không phù hợp để làm cho mọi thứ trở nên linh hoạt một cách lố bịch, vì thời gian bạn dành cho việc trừu tượng hóa sẽ không chứng minh được lợi ích.

Truyền các giao diện thay vì các lớp cụ thể đôi khi có nghĩa là bạn có thể dễ dàng trao đổi đọc từ một tệp cho luồng mạng aa. Tuy nhiên, đối với một số lượng lớn các dự án phần mềm, loại linh hoạt đó sẽ không bao giờ cần thiết, và bạn cũng có thể chỉ cần vượt qua các lớp tệp cụ thể và gọi nó là một ngày và tiết kiệm các tế bào não của bạn.

Một phần của nghệ thuật phát triển phần mềm là có ý thức tốt về những gì có thể thay đổi khi thời gian trôi qua, và những gì không. Đối với những thứ có khả năng thay đổi, hãy sử dụng các giao diện và các khái niệm RẮN khác. Đối với những thứ không có, hãy sử dụng YAGNI và chỉ truyền các loại cụ thể, quên các lớp xuất xưởng, quên tất cả cấu hình và cấu hình thời gian chạy, v.v. và quên rất nhiều trừu tượng RẮN. Theo kinh nghiệm của tôi, phương pháp YAGNI đã được chứng minh là chính xác thường xuyên hơn nhiều so với không.


19
Giới thiệu đầu tiên của tôi về RẮN là khoảng 15 năm trước trên một hệ thống mới mà chúng tôi đang xây dựng. Tất cả chúng tôi đã uống người đàn ông viện trợ kool. Nếu bất cứ ai đề cập đến bất cứ điều gì nghe giống như YAGNI, chúng tôi sẽ giống như "Pfffft ... plebeian". Tôi đã có vinh dự (kinh dị?) Khi xem hệ thống đó phát triển trong suốt thập kỷ tiếp theo. Nó trở thành một mớ hỗn độn khó sử dụng mà không ai có thể hiểu được, ngay cả những người sáng lập chúng tôi. Kiến trúc sư yêu RẮN. Những người thực sự kiếm được tình yêu sống của họ YAGNI. Không phải là hoàn hảo, nhưng YAGNI gần hoàn hảo hơn và nên là mặc định của bạn nếu bạn không biết bạn đang làm gì. :-)
Calphool

11
@NWard Vâng, chúng tôi đã làm điều đó trong một dự án. Đã đi hạt với nó. Bây giờ các bài kiểm tra của chúng tôi không thể đọc hoặc duy trì, một phần vì quá chế nhạo. Trên hết, vì tiêm phụ thuộc, nên phía sau phải điều hướng mã khi bạn đang cố gắng tìm ra điều gì đó. RẮN không phải là viên đạn bạc. YAGNI không phải là viên đạn bạc. Kiểm tra tự động không phải là một viên đạn bạc. Không gì có thể cứu bạn khỏi việc làm việc chăm chỉ để suy nghĩ về những gì bạn đang làm và đưa ra quyết định về việc nó sẽ giúp đỡ hay cản trở công việc của bạn hoặc của người khác.
jpmc26

22
Rất nhiều tình cảm chống RẮN ở đây. RẮN và YAGNI không phải là hai đầu của một phổ. Chúng giống như tọa độ X và Y trên biểu đồ. Một hệ thống tốt có rất ít mã thừa (YAGNI) VÀ tuân theo các nguyên tắc RẮN.
Stephen

31
Meh, (a) Tôi không đồng ý rằng RẮN = enterprisey và (b) toàn bộ quan điểm của RẮN là chúng ta có xu hướng trở thành những người dự báo cực kỳ kém về những gì sẽ cần. Tôi phải đồng ý với @Stephen ở đây. YAGNI nói rằng chúng ta không nên cố gắng lường trước các yêu cầu trong tương lai mà không được nêu rõ ràng ngày hôm nay. RẮN nói rằng chúng ta nên mong đợi thiết kế phát triển theo thời gian và áp dụng các kỹ thuật đơn giản nhất định để tạo điều kiện thuận lợi cho nó. Họ không loại trừ lẫn nhau; cả hai đều là kỹ thuật để thích ứng với các yêu cầu thay đổi. Các vấn đề thực sự xảy ra khi bạn cố gắng thiết kế cho các yêu cầu không rõ ràng hoặc rất xa.
Aaronaught

8
"Bạn có thể dễ dàng trao đổi việc đọc từ một tệp cho luồng mạng aa" - đây là một ví dụ điển hình trong đó một mô tả quá đơn giản về DI khiến mọi người lạc lối. Mọi người đôi khi nghĩ (có hiệu lực), "phương pháp này sẽ sử dụng một File, vì vậy thay vào đó, nó sẽ thực hiện một IFilecông việc". Sau đó, họ không thể dễ dàng thay thế một luồng mạng, vì họ yêu cầu giao diện quá mức và có các thao tác trong IFilephương thức thậm chí không sử dụng, không áp dụng cho các ổ cắm, vì vậy một ổ cắm không thể thực hiện IFile. Một trong những điều DI không phải là viên đạn bạc, là phát minh ra sự trừu tượng đúng (giao diện) :-)
Steve Jessop

11

Theo cách nói của giáo dân:

Áp dụng DIP vừa dễ dàng vừa thú vị . Không có được thiết kế ngay lần thử đầu tiên là không đủ lý do để từ bỏ hoàn toàn trên DIP.

  • Thông thường các IDE giúp bạn thực hiện kiểu tái cấu trúc đó, một số thậm chí cho phép bạn trích xuất giao diện ra khỏi một lớp đã được triển khai
  • Gần như không thể có được thiết kế ngay lần đầu tiên
  • Quy trình công việc bình thường liên quan đến việc thay đổi và suy nghĩ lại các giao diện trong giai đoạn phát triển đầu tiên
  • Khi sự phát triển phát triển, nó trưởng thành và bạn sẽ có ít lý do hơn để sửa đổi các giao diện
  • Trong giai đoạn nâng cao, các giao diện (thiết kế) sẽ hoàn thiện và hầu như không thay đổi
  • Từ thời điểm đó, bạn bắt đầu gặt hái những lợi ích, vì ứng dụng của bạn được mở để mở rộng quy mô.

Mặt khác, lập trình với các giao diện và OOD có thể mang lại niềm vui cho nghề lập trình đôi khi cũ kỹ.

Một số người nói rằng nó thêm phức tạp nhưng tôi nghĩ rằng opossite là đúng. Ngay cả đối với các dự án nhỏ. Nó làm cho thử nghiệm / chế nhạo dễ dàng hơn. Nó làm cho mã của bạn có ít hơn nếu có bất kỳ casecâu lệnh hoặc lồng nhau nào ifs. Nó làm giảm sự phức tạp theo chu kỳ và khiến bạn suy nghĩ theo những cách mới mẻ. Nó làm cho việc lập trình giống với thiết kế và sản xuất trong thế giới thực hơn.


5
Tôi không biết ngôn ngữ hoặc IDE nào đang được OP sử dụng, nhưng trong VS 2013, thật đơn giản để làm việc với các giao diện, trích xuất giao diện và triển khai chúng, và rất quan trọng nếu TDD được sử dụng. Không có chi phí phát triển thêm để phát triển bằng cách sử dụng các nguyên tắc này.
stephenbayer

Tại sao câu trả lời này lại nói về DI nếu câu hỏi là về DIP? DIP là một khái niệm từ những năm 1990, trong khi DI là từ năm 2004. Chúng rất khác nhau.
Rogério

1
(Nhận xét trước đây của tôi có nghĩa là cho một câu trả lời khác; bỏ qua nó.) "Lập trình cho giao diện" chung chung hơn nhiều so với DIP, nhưng nó không phải là làm cho mỗi lớp thực hiện một giao diện riêng. Và nó chỉ làm cho "thử nghiệm / chế nhạo" dễ dàng hơn nếu các công cụ kiểm tra / chế nhạo gặp phải những hạn chế nghiêm trọng.
Rogério

@ Rogério Thông thường khi sử dụng DI, không phải lớp nào cũng thực hiện một giao diện riêng. Một giao diện đang được thực hiện bởi một số lớp là phổ biến.
Tulains Córdova

@ Rogério Tôi đã sửa câu trả lời của mình, mỗi lần tôi nhắc đến DI tôi có nghĩa là DIP.
Tulains Córdova

9

Sử dụng đảo ngược phụ thuộc nơi nó có ý nghĩa.

Một ví dụ cực đoan là lớp "chuỗi" được bao gồm trong nhiều ngôn ngữ. Nó đại diện cho một khái niệm nguyên thủy, về cơ bản là một mảng các ký tự. Giả sử bạn có thể thay đổi lớp lõi này, sẽ không có ý nghĩa gì khi sử dụng DI ở đây vì bạn sẽ không bao giờ cần phải trao đổi trạng thái nội bộ với thứ khác.

Nếu bạn có một nhóm các đối tượng được sử dụng nội bộ trong một mô-đun không được tiếp xúc với các mô-đun khác hoặc được sử dụng lại ở bất cứ đâu, có lẽ không đáng để sử dụng DI.

Theo tôi, có hai nơi DI nên được sử dụng tự động:

  1. Trong các mô-đun được thiết kế để mở rộng. Nếu toàn bộ mục đích của một mô-đun là để mở rộng nó và thay đổi hành vi, thì việc nướng DI ngay từ đầu sẽ rất hợp lý.

  2. Trong các mô-đun mà bạn đang tái cấu trúc cho mục đích tái sử dụng mã. Có lẽ bạn đã mã hóa một lớp để làm một cái gì đó, sau đó nhận ra rằng với một bộ tái cấu trúc, bạn có thể tận dụng mã đó ở nơi khác và cần phải làm như vậy . Đó là một ứng cử viên tuyệt vời cho DI và những thay đổi mở rộng khác.

Các khóa ở đây đang sử dụng nó khi cần thiết bởi vì nó sẽ giới thiệu thêm độ phức tạp và đảm bảo bạn đo được nhu cầu đó thông qua các yêu cầu kỹ thuật (điểm một) hoặc xem xét mã định lượng (điểm hai).

DI là một công cụ tuyệt vời, nhưng cũng giống như bất kỳ công cụ * nào, nó có thể bị lạm dụng hoặc sử dụng sai.

* Ngoại lệ cho quy tắc trên: cưa ngược là công cụ hoàn hảo cho mọi công việc. Nếu nó không khắc phục vấn đề của bạn, nó sẽ loại bỏ nó. Vĩnh viễn.


3
Điều gì xảy ra nếu "vấn đề của bạn" là một lỗ trên tường? Một cái cưa sẽ không loại bỏ nó; nó sẽ làm cho nó tồi tệ hơn ;)
Mason Wheeler

3
@MasonWheeler với chiếc cưa mạnh mẽ và thú vị, "lỗ trên tường" có thể biến thành "ô cửa", một tài sản hữu ích :-)

1
Bạn không thể sử dụng cưa để tạo ra một bản vá cho lỗ?
JeffO

Mặc dù có một số lợi thế khi có loại không thể mở rộng String, nhưng có nhiều trường hợp các biểu diễn thay thế sẽ hữu ích nếu loại đó có một tập hợp các thao tác ảo tốt (ví dụ: sao chép một chuỗi con vào một phần cụ thể của một short[]báo cáo, cho dù chuỗi con có hoặc chỉ chứa ASCII, cố gắng sao chép một chuỗi con được cho là chỉ chứa ASCII vào một phần xác định của a byte[], v.v.) Các khung quá xấu không có kiểu chuỗi của chúng thực hiện bất kỳ giao diện liên quan đến chuỗi hữu ích nào.
supercat

1
Tại sao câu trả lời này lại nói về DI nếu câu hỏi là về DIP? DIP là một khái niệm từ những năm 1990, trong khi DI là từ năm 2004. Chúng rất khác nhau.
Rogério

5

Dường như với tôi rằng câu hỏi ban đầu là thiếu một phần quan điểm của DIP.

Lý do tôi hoài nghi là vì chúng tôi đang trả một số giá cho việc tuân theo nguyên tắc này. Giả sử, tôi cần triển khai tính năng Z. Sau khi phân tích, tôi kết luận rằng tính năng Z bao gồm chức năng A, B và C. Tôi tạo ra một lớp Z mê hoặc, thông qua các giao diện, sử dụng các lớp A, B và C. Tôi bắt đầu mã hóa triển khai và đến một lúc nào đó tôi nhận ra rằng tác vụ Z thực sự bao gồm chức năng A, B và D. Bây giờ tôi cần loại bỏ giao diện C, nguyên mẫu lớp C và viết giao diện và lớp D riêng biệt. Không có giao diện, chỉ có lớp sóng sẽ cần phải được thay thế.

Để thực sự tận dụng lợi thế của DIP, trước tiên bạn sẽ tạo lớp Z và gọi nó là chức năng của các lớp A, B và C (chưa được phát triển). Điều này cung cấp cho bạn API cho các lớp A, B và C. Sau đó, bạn đi và tạo các lớp A, B và C và điền vào các chi tiết. Bạn thực sự nên tạo ra sự trừu tượng mà bạn cần khi bạn tạo lớp Z, hoàn toàn dựa trên những gì lớp Z cần. Bạn thậm chí có thể viết các bài kiểm tra xung quanh lớp Z trước khi các lớp A, B hoặc C thậm chí được viết.

Hãy nhớ rằng DIP nói rằng "Các mô-đun cấp cao không nên phụ thuộc vào các mô-đun cấp thấp. Cả hai nên phụ thuộc vào trừu tượng hóa."

Một khi bạn đã tìm ra lớp Z cần gì và cách mà nó muốn có được thứ nó cần, thì bạn có thể điền vào các chi tiết. Chắc chắn, đôi khi các thay đổi sẽ cần phải được thực hiện cho lớp Z, nhưng 99% thời gian sẽ không xảy ra.

Sẽ không bao giờ có lớp D vì bạn đã làm việc rằng Z cần A, B và C trước khi chúng được viết. Một sự thay đổi trong các yêu cầu là một câu chuyện khác nhau hoàn toàn.


5

Câu trả lời ngắn gọn là "hầu như không bao giờ", nhưng trên thực tế, có một vài nơi mà DIP không có ý nghĩa:

  1. Các nhà máy hoặc nhà xây dựng, có nhiệm vụ tạo ra các đối tượng. Đây thực chất là các "nút lá" trong một hệ thống hoàn toàn chấp nhận IoC. Tại một số điểm, một cái gì đó phải thực sự tạo ra các đối tượng của bạn và không thể phụ thuộc vào bất cứ điều gì khác để làm điều đó. Trong nhiều ngôn ngữ, một container IoC có thể làm điều đó cho bạn, nhưng đôi khi bạn cần thực hiện theo cách cũ.

  2. Triển khai cấu trúc dữ liệu và thuật toán. Nói chung, trong những trường hợp này, các đặc điểm nổi bật mà bạn tối ưu hóa (như thời gian chạy và độ phức tạp tiệm cận) phụ thuộc vào các loại dữ liệu cụ thể được sử dụng. Nếu bạn đang thực hiện bảng băm, bạn thực sự cần biết rằng bạn đang làm việc với một mảng để lưu trữ, không phải là danh sách được liên kết và chỉ có bảng mới biết cách phân bổ các mảng đúng cách. Bạn cũng không muốn vượt qua trong một mảng có thể thay đổi và yêu cầu người gọi phá vỡ bảng băm của bạn bằng cách thay đổi nội dung của nó.

  3. Các lớp mô hình miền . Những điều này triển khai logic kinh doanh của bạn và (hầu hết thời gian) chỉ có ý nghĩa khi có một triển khai, bởi vì (hầu hết thời gian) bạn chỉ phát triển phần mềm cho một doanh nghiệp. Mặc dù một số lớp mô hình miền có thể được xây dựng bằng các lớp mô hình miền khác, nhưng điều này thường sẽ dựa trên từng trường hợp cụ thể. Vì các đối tượng mô hình miền không bao gồm bất kỳ chức năng nào có thể bị chế giễu một cách hữu ích, nên không có lợi ích kiểm tra hoặc khả năng bảo trì cho DIP.

  4. Bất kỳ đối tượng nào được cung cấp dưới dạng API bên ngoài và cần tạo các đối tượng khác, có chi tiết triển khai mà bạn không muốn phơi bày công khai. Điều này thuộc danh mục chung của "thiết kế thư viện khác với thiết kế ứng dụng". Một thư viện hoặc khung có thể sử dụng DI tự do trong nội bộ, nhưng cuối cùng sẽ phải thực hiện một số công việc thực tế, nếu không đó không phải là một thư viện rất hữu ích. Giả sử bạn đang phát triển một thư viện mạng; bạn thực sự không muốn người tiêu dùng có thể cung cấp việc thực hiện một ổ cắm riêng. Bạn có thể sử dụng nội dung trừu tượng của một ổ cắm, nhưng API bạn trưng ra cho người gọi sẽ tạo ra các ổ cắm riêng.

  5. Kiểm tra đơn vị, và kiểm tra tăng gấp đôi. Fakes và stub được cho là làm một việc và làm nó đơn giản. Nếu bạn có một giả mạo đủ phức tạp để lo lắng về việc có nên thực hiện tiêm phụ thuộc hay không, thì có lẽ nó quá phức tạp (có lẽ vì việc triển khai một giao diện cũng quá phức tạp).

Có thể có nhiều hơn; đây là những cái tôi thấy trên cơ sở hơi thường xuyên.


Làm thế nào về "bất cứ lúc nào bạn đang làm việc trong một ngôn ngữ năng động"?
Kevin

Không? Tôi làm rất nhiều công việc trong JavaScript và nó vẫn áp dụng tốt như nhau ở đó. Tuy nhiên, chữ "O" và "I" trong RẮN có thể hơi mờ.
Aaronaught

Hả ... tôi thấy rằng các loại hạng nhất của Python kết hợp với gõ vịt làm cho nó ít cần thiết hơn.
Kevin

DIP hoàn toàn không có gì để làm với hệ thống loại. Và theo cách nào thì "loại hạng nhất" là duy nhất đối với trăn? Khi bạn muốn kiểm tra một cái gì đó một cách cô lập, bạn phải thay thế thử nghiệm nhân đôi cho sự phụ thuộc của nó. Các phép nhân đôi này có thể là các triển khai thay thế của một giao diện (bằng các ngôn ngữ được nhập tĩnh) hoặc chúng có thể là các đối tượng ẩn danh hoặc các loại thay thế xảy ra để có cùng phương thức / chức năng trên chúng (gõ vịt). Trong cả hai trường hợp, bạn vẫn cần một cách để thực sự thay thế một thể hiện.
Aaronaught

1
@Kevin python hầu như không phải là ngôn ngữ đầu tiên sở hữu kiểu gõ động hoặc giả lỏng. Nó cũng hoàn toàn không liên quan. Câu hỏi không phải là kiểu của một đối tượng mà là cách thức / nơi mà đối tượng được tạo ra. Khi một đối tượng tạo ra các phụ thuộc của riêng nó, bạn buộc phải kiểm tra đơn vị những gì nên là chi tiết triển khai, bằng cách thực hiện những điều khủng khiếp như loại bỏ các hàm tạo của các lớp mà API công khai không đề cập đến. Và quên đi việc kiểm tra, pha trộn hành vi và xây dựng đối tượng chỉ đơn giản là dẫn đến khớp nối chặt chẽ. Gõ vịt không giải quyết được một trong những vấn đề đó.
Aaronaught

2

Một số dấu hiệu bạn có thể đang áp dụng DIP ở mức quá vi mô, trong đó nó không mang lại giá trị:

  • bạn có một cặp C / CImpl hoặc IC / C, chỉ với một triển khai duy nhất của giao diện đó
  • các chữ ký trong giao diện và cách triển khai của bạn khớp với từng chữ một (vi phạm nguyên tắc DRY)
  • bạn thường xuyên thay đổi C và CImpl cùng một lúc.
  • C là nội bộ cho dự án của bạn và không được chia sẻ bên ngoài dự án của bạn dưới dạng thư viện.
  • bạn thất vọng vì F3 trong Eclipse / F12 trong Visual Studio đưa bạn đến giao diện thay vì lớp thực tế

Nếu đây là những gì bạn đang thấy, có lẽ bạn nên gọi Z trực tiếp và bỏ qua giao diện.

Ngoài ra, tôi không nghĩ đến việc trang trí phương thức bằng khung proxy phụ thuộc / proxy động (Spring, Java EE) giống như cách RẮN RẮN thực sự - đây giống như một chi tiết triển khai về cách trang trí phương thức hoạt động trong ngăn xếp công nghệ đó. Cộng đồng Java EE coi đó là một cải tiến mà bạn không cần các cặp Foo / FooImpl như bạn đã từng sử dụng ( tham khảo ). Ngược lại, Python hỗ trợ trang trí chức năng như một tính năng ngôn ngữ hạng nhất.

Xem thêm bài blog này .


0

Nếu bạn luôn đảo ngược sự phụ thuộc của mình, thì tất cả sự phụ thuộc của bạn bị đảo lộn. Điều đó có nghĩa là nếu bạn bắt đầu với mã lộn xộn với một nút phụ thuộc, đó là những gì bạn vẫn (thực sự) có, chỉ cần đảo ngược. Đó là nơi bạn gặp phải vấn đề mà mọi thay đổi đối với việc triển khai cũng cần thay đổi giao diện của nó.

Điểm của nghịch đảo phụ thuộc là bạn đảo ngược có chọn lọc các phụ thuộc đang làm cho mọi thứ rối. Những người nên đi từ A đến B đến C vẫn làm như vậy, đó là những người đi từ C đến A mà bây giờ đi từ A đến C.

Kết quả phải là một biểu đồ phụ thuộc không có chu kỳ - DAG. Có nhiều công cụ khác nhau sẽ kiểm tra thuộc tính này và vẽ biểu đồ.

Để được giải thích đầy đủ hơn, xem bài viết này :

Bản chất của việc áp dụng Nguyên tắc đảo ngược phụ thuộc chính xác là:

Tách mã / dịch vụ / Nhận bạn phụ thuộc vào một giao diện và cách triển khai. Giao diện cấu trúc lại sự phụ thuộc trong thuật ngữ của mã sử dụng nó, việc triển khai thực hiện nó theo các kỹ thuật cơ bản của nó.

Việc thực hiện vẫn còn đó. Nhưng giao diện bây giờ có một chức năng khác (và sử dụng một thuật ngữ / ngôn ngữ khác), mô tả một cái gì đó mà mã sử dụng có thể làm. Di chuyển nó đến gói đó. Bằng cách không đặt giao diện và triển khai trong cùng một gói, sự phụ thuộc (hướng của) được đảo ngược từ người dùng → thực hiện sang thực hiện → người dùng.

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.