Sự khác biệt giữa các mẫu Định vị dịch vụ tiêm và dịch vụ phụ thuộc là gì?


304

Cả hai mô hình có vẻ như là một thực hiện của nguyên tắc đảo ngược kiểm soát. Đó là, một đối tượng không nên biết cách xây dựng các phụ thuộc của nó.

Dependency Injection (DI) dường như sử dụng hàm tạo hoặc setter để "tiêm" các phụ thuộc của nó.

Ví dụ về việc sử dụng Con Contortor tiêm:

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo(IBar bar)
  {
    this.bar = bar;
  }

  //...
}

Bộ định vị dịch vụ dường như sử dụng một "thùng chứa", kết nối các phụ thuộc của nó và cung cấp cho thanh đó.

Ví dụ về việc sử dụng Trình định vị dịch vụ:

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo()
  {
    this.bar = Container.Get<IBar>();
  }

  //...
}

Bởi vì các phụ thuộc của chúng ta chỉ là các đối tượng, các phụ thuộc này có các phụ thuộc, thậm chí còn có nhiều phụ thuộc hơn, v.v. Do đó, Inversion of Control Container (hoặc DI Container) đã ra đời. Ví dụ: Castle Windsor, Ninject, Bản đồ cấu trúc, Mùa xuân, v.v.)

Nhưng Container IOC / DI trông giống hệt Bộ định vị dịch vụ. Có phải gọi nó là DI Container là một tên xấu? Có phải IOC / DI Container chỉ là một loại Định vị dịch vụ khác không? Là sắc thái trong thực tế là chúng ta sử dụng DI Container hầu hết khi chúng ta có nhiều Phụ thuộc?


13
Đảo ngược điều khiển có nghĩa là "một đối tượng không nên biết cách xây dựng các phụ thuộc của nó"?!? Đó là một cái mới đối với tôi. Không, thực sự, đó không phải là "đảo ngược kiểm soát" nghĩa là gì. Xem martinfowler.com/bliki/InversionOfControl.html Bài báo đó thậm chí còn cung cấp tài liệu tham khảo cho từ nguyên của thuật ngữ, có từ những năm 1980.
Rogério


1
Mark Seemann lập luận Bộ định vị dịch vụ là mẫu chống ( blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Potype ). Ngoài ra, tôi thấy sơ đồ (tìm thấy ở đây, stackoverflow.com/a/9503612/1977871 ) hữu ích để hiểu tình trạng DI và SL. Hi vọng điêu nay co ich.
VivekDev

Câu trả lời:


181

Sự khác biệt có vẻ nhẹ, nhưng ngay cả với ServiceLocator, lớp vẫn chịu trách nhiệm tạo ra các phụ thuộc của nó. Nó chỉ sử dụng công cụ định vị để làm điều đó. Với DI, lớp được cung cấp các phụ thuộc của nó. Nó không biết, cũng không quan tâm họ đến từ đâu. Một kết quả quan trọng của điều này là ví dụ DI dễ kiểm tra đơn vị hơn nhiều - bởi vì bạn có thể vượt qua nó để thực hiện các đối tượng phụ thuộc của nó. Bạn có thể kết hợp cả hai - và tiêm định vị dịch vụ (hoặc một nhà máy), nếu bạn muốn.


20
Ngoài ra, bạn có thể sử dụng cả hai khi xây dựng một lớp. Hàm tạo mặc định có thể sử dụng SL để truy xuất các phụ thuộc và chuyển chúng đến hàm tạo "thực" nhận các phụ thuộc đó. Bạn có được điều tốt nhất của cả hai thế giới.
Cấp Palin

6
Không, ServiceLocator là người chịu trách nhiệm khởi tạo việc triển khai chính xác cho một phụ thuộc nhất định (plugin). Trong trường hợp của DI, DI "container" là người chịu trách nhiệm cho việc đó.
Rogério

5
@Rogerio có nhưng lớp vẫn phải biết về Trình định vị dịch vụ ... đó là hai sự thiếu sót. Cũng thường xuyên hơn không, tôi đã thấy Đại diện dịch vụ định vị cho bộ chứa DI để tra cứu đặc biệt cho các đối tượng nhất thời cần hỗ trợ dịch vụ.
Adam Gent

2
@Adam Tôi không nói rằng Bộ định vị dịch vụ sẽ ủy quyền cho một container DI. Đây là hai mẫu loại trừ lẫn nhau, như được mô tả trong bài viết "chính thức" . Đối với tôi, Bộ định vị dịch vụ có một lợi thế rất lớn so với DI trong thực tế: việc sử dụng bộ chứa DI mời lạm dụng (mà tôi đã thấy nhiều lần), trong khi sử dụng Bộ định vị dịch vụ thì không.
Rogério

3
"Một kết quả quan trọng của điều này là ví dụ DI dễ kiểm tra đơn vị hơn nhiều - bởi vì bạn có thể vượt qua nó để thực hiện các đối tượng phụ thuộc của nó." Không đúng. Trong các thử nghiệm đơn vị của bạn, một cuộc gọi đến chức năng đăng ký trong bộ định vị dịch vụ có thể được sử dụng để dễ dàng thêm các giả vào sổ đăng ký.
Drumbeg

93

Khi bạn sử dụng công cụ định vị dịch vụ, mỗi lớp sẽ có sự phụ thuộc vào công cụ định vị dịch vụ của bạn. Đây không phải là trường hợp với tiêm phụ thuộc. Trình tiêm phụ thuộc thường sẽ chỉ được gọi một lần khi khởi động để tiêm phụ thuộc vào một số lớp chính. Các lớp mà lớp chính này phụ thuộc vào sẽ đệ quy các phụ thuộc của chúng, cho đến khi bạn có một biểu đồ đối tượng hoàn chỉnh.

Một so sánh tốt: http://martinfowler.com/articles/injection.html

Nếu bộ tiêm phụ thuộc của bạn trông giống như bộ định vị dịch vụ, trong đó các lớp gọi trực tiếp bộ tiêm, thì đó có thể không phải là bộ tiêm phụ thuộc, mà là bộ định vị dịch vụ.


17
Nhưng làm thế nào để bạn xử lý trường hợp bạn phải tạo các đối tượng trong thời gian chạy? Nếu bạn tạo chúng bằng tay với "mới", bạn không thể sử dụng DI. Nếu bạn gọi khung DI để được giúp đỡ, bạn đang phá vỡ mô hình. Vì vậy, những lựa chọn còn lại?
Boris

9
@Boris Tôi có cùng một vấn đề và quyết định tiêm các nhà máy cụ thể của lớp. Không xinh nhưng đã hoàn thành công việc. Rất thích nhìn thấy một giải pháp đẹp hơn.
Charlie Rudenstål

Liên kết trực tiếp để so sánh: martinfowler.com/articles/ từ
Teoman shipahi

2
@Boris Nếu tôi cần xây dựng các đối tượng mới một cách nhanh chóng, tôi sẽ tiêm một Nhà máy Trừu tượng cho các đối tượng nói trên. Điều này sẽ tương tự như tiêm một bộ định vị dịch vụ trong trường hợp này nhưng cung cấp một giao diện cụ thể, thống nhất, thời gian biên dịch, để xây dựng các đối tượng có liên quan và làm cho các phụ thuộc rõ ràng.
LivePastTheEnd 27/2/2017

51

Các bộ định vị dịch vụ ẩn các phụ thuộc - bạn không thể biết bằng cách nhìn vào một đối tượng xem nó có chạm vào cơ sở dữ liệu hay không (ví dụ) khi nó nhận được các kết nối từ một bộ định vị. Với tiêm phụ thuộc (ít nhất là tiêm constructor), các phụ thuộc là rõ ràng.

Hơn nữa, các bộ định vị dịch vụ phá vỡ đóng gói vì chúng cung cấp một điểm truy cập toàn cầu vào các phụ thuộc của các đối tượng khác. Với định vị dịch vụ, như với bất kỳ singleton nào :

việc xác định các điều kiện trước và sau cho giao diện của đối tượng khách trở nên khó khăn, bởi vì các hoạt động triển khai của nó có thể được can thiệp từ bên ngoài.

Với việc tiêm phụ thuộc, một khi các phụ thuộc của đối tượng được chỉ định, chúng sẽ nằm dưới sự kiểm soát của chính đối tượng đó.


3
Tôi thích "Singletons được coi là ngu ngốc", steve.yegge.googlepages.com/singleton-considered-stool
Charles Graham

2
Tôi yêu ol 'Steve Yegge và tiêu đề của bài viết đó rất hay, nhưng tôi nghĩ rằng bài báo tôi đã trích dẫn và "Singletons là những kẻ nói dối bệnh lý" ( misko.hevery.com/2008/08/17/singletons-are-pathological- những kẻ nói dối ) làm cho một trường hợp tốt hơn chống lại ma quỷ đặc biệt của công cụ định vị dịch vụ.
Jeff Sternal

Câu trả lời này là đúng nhất bởi vì nó xác định tốt nhất một bộ định vị dịch vụ: "Một lớp ẩn các phụ thuộc của nó." Lưu ý rằng việc tạo ra một phụ thuộc bên trong, trong khi thường không phải là một điều tốt, không làm cho một lớp định vị dịch vụ. Ngoài ra, việc phụ thuộc vào một container là một vấn đề nhưng không phải là "vấn đề" xác định rõ nhất một bộ định vị dịch vụ.
Sam

1
With dependency injection (at least constructor injection) the dependencies are explicit.. Vui lòng giải thích.
FindOutIslamNow

Như trên, tôi không thể thấy SL làm cho sự phụ thuộc ít rõ ràng hơn DI ...
Michał Powłoka

38

Martin Fowler tuyên bố :

Với trình định vị dịch vụ, lớp ứng dụng yêu cầu nó rõ ràng bằng một thông báo cho trình định vị. Với tiêm không có yêu cầu rõ ràng, dịch vụ xuất hiện trong lớp ứng dụng - do đó đảo ngược quyền kiểm soát.

Nói tóm lại: Định vị dịch vụ và tiêm phụ thuộc chỉ là các triển khai của Nguyên tắc đảo ngược phụ thuộc.

Nguyên tắc quan trọng là Phụ thuộc vào Trừu tượng, chứ không phải dựa trên cụ thể. Điều này sẽ làm cho thiết kế phần mềm của bạn liên kết với nhau một cách lỏng lẻo.

Bạn có thể sử dụng một trong những phù hợp nhất với nhu cầu của bạn. Đối với một ứng dụng lớn, có một cơ sở mã lớn, bạn nên sử dụng Trình định vị dịch vụ tốt hơn, bởi vì Dependency Injection sẽ yêu cầu nhiều thay đổi hơn đối với cơ sở mã của bạn.

Bạn có thể kiểm tra bài đăng này: Nghịch đảo phụ thuộc: Định vị dịch vụ hoặc Tiêm phụ thuộc

Cũng là tác phẩm kinh điển: Nghịch đảo các container kiểm soát và mô hình tiêm phụ thuộc của Martin Fowler

Thiết kế các lớp học tái sử dụng của Ralph E. Johnson & Brian Foote

Tuy nhiên, thứ mở ra cho tôi là: ASP.NET MVC: Resolve hay Meth? Đó là vấn đề của Dino Esposito


Tóm tắt tuyệt vời: "Định vị dịch vụ và tiêm phụ thuộc chỉ là triển khai Nguyên tắc đảo ngược phụ thuộc."
Hans

Và ông cũng nói: Sự khác biệt chính là với Trình định vị dịch vụ, mọi người dùng dịch vụ đều có sự phụ thuộc vào trình định vị. Trình định vị có thể ẩn các phụ thuộc vào các triển khai khác, nhưng bạn cần phải xem trình định vị. Vì vậy, quyết định giữa người định vị và người tiêm phụ thuộc vào việc phụ thuộc đó có phải là vấn đề hay không.
chương trình

1
ServiceLocator và DI không liên quan gì đến "Nguyên tắc đảo ngược phụ thuộc" (DIP). DIP là một cách để làm cho một thành phần cấp cao có thể tái sử dụng nhiều hơn, bằng cách thay thế một phụ thuộc thời gian biên dịch vào một thành phần cấp thấp bằng một phụ thuộc vào một loại trừu tượng được xác định cùng với thành phần cấp cao, được thực hiện bởi cấp thấp cấp thành phần; theo cách này, sự phụ thuộc thời gian biên dịch bị đảo ngược, vì bây giờ nó là mức độ thấp phụ thuộc vào mức độ cao. Ngoài ra, lưu ý rằng bài viết của Martin Fowler giải thích rằng DI và IoC không giống nhau.
Rogério

23

Một lớp sử dụng hàm tạo DI chỉ ra việc tiêu thụ mã rằng có các phụ thuộc được thỏa mãn. Nếu lớp sử dụng SL bên trong để truy xuất các phụ thuộc như vậy, mã tiêu thụ không nhận thức được các phụ thuộc. Điều này có thể trên bề mặt có vẻ tốt hơn, nhưng nó thực sự hữu ích để biết về bất kỳ phụ thuộc rõ ràng. Nó là tốt hơn từ một quan điểm kiến ​​trúc. Và khi thực hiện kiểm thử, bạn phải biết liệu một lớp có cần một số phụ thuộc nhất định hay không và định cấu hình SL để cung cấp các phiên bản giả mạo phù hợp của các phụ thuộc đó. Với DI, chỉ cần vượt qua trong hàng giả. Không phải là một sự khác biệt lớn, nhưng nó là ở đó.

DI và SL có thể làm việc cùng nhau, mặc dù. Thật hữu ích khi có một vị trí trung tâm cho các phụ thuộc chung (ví dụ: cài đặt, logger, v.v.). Đưa ra một lớp bằng cách sử dụng các deps như vậy, bạn có thể tạo một hàm tạo "thực" nhận các deps và một hàm tạo mặc định (không tham số) lấy từ SL và chuyển tiếp đến hàm tạo "thực".

EDIT: và tất nhiên, khi bạn sử dụng SL, bạn sẽ giới thiệu một số khớp nối với thành phần đó. Thật là mỉa mai, vì ý tưởng của chức năng như vậy là để khuyến khích sự trừu tượng và giảm khớp nối. Các mối quan tâm có thể được cân bằng, và nó phụ thuộc vào số lượng nơi bạn sẽ cần sử dụng SL. Nếu được thực hiện như đề xuất ở trên, chỉ trong hàm tạo của lớp mặc định.


Hấp dẫn! Tôi đang sử dụng cả DI và SL, nhưng không phải với hai hàm tạo. Ba hoặc bốn phụ thuộc nhàm chán nhất thường cần (cài đặt, v.v ...) có được từ SL khi đang di chuyển. Mọi thứ khác được tiêm constructor. Đó là một chút xấu xí, nhưng thực dụng.
maaartinus

10

Cả hai đều là kỹ thuật triển khai của IoC. Ngoài ra còn có các mẫu khác thực hiện Inversion of Control:

  • Mô hình nhà máy
  • Dịch vụ định vị
  • Container DI (IoC)
  • Tiêm phụ thuộc (tiêm constructor, tiêm tham số (nếu không bắt buộc), tiêm setter tiêm giao diện) ...

Trình định vị dịch vụ và DI Container có vẻ giống nhau hơn, cả hai đều sử dụng một container để xác định các phụ thuộc, ánh xạ trừu tượng đến việc triển khai cụ thể.

Sự khác biệt chính là cách các phụ thuộc được định vị, trong Bộ định vị dịch vụ, mã máy khách yêu cầu các phụ thuộc, trong DI Container, chúng tôi sử dụng một thùng chứa để tạo tất cả các đối tượng và nó chèn phụ thuộc làm tham số (hoặc thuộc tính của hàm tạo).


7

Trong dự án cuối cùng của tôi, tôi sử dụng cả hai. Tôi sử dụng tiêm phụ thuộc để kiểm tra đơn vị. Tôi sử dụng công cụ định vị dịch vụ để ẩn việc triển khai và phụ thuộc vào bộ chứa IoC của tôi. và vâng! Khi bạn sử dụng một trong các container IoC (Unity, Ninject, Windsor Castle), bạn phụ thuộc vào nó. Và một khi nó đã lỗi thời hoặc vì một số lý do nếu bạn muốn trao đổi nó, bạn sẽ / có thể cần phải thay đổi triển khai của mình - ít nhất là root thành phần. Nhưng định vị dịch vụ trừu tượng giai đoạn đó.

Làm thế nào bạn sẽ không phụ thuộc vào container IoC của bạn? Bạn sẽ cần phải tự bọc nó (đó là một ý tưởng tồi) hoặc bạn sử dụng Trình định vị dịch vụ định cấu hình bộ chứa IoC của bạn. Vì vậy, bạn sẽ báo cho bộ định vị dịch vụ để nhận giao diện nào bạn cần và nó sẽ gọi bộ chứa IoC được cấu hình để truy xuất giao diện đó.

Trong trường hợp của tôi, tôi sử dụng ServiceLocator , một thành phần khung. Và sử dụng Unity cho container IoC. Nếu trong tương lai tôi cần trao đổi bộ chứa IoC của mình sang Ninject, tất cả những gì tôi cần làm là tôi cần định cấu hình bộ định vị Dịch vụ của mình để sử dụng Ninject thay vì Unity. Dễ dàng di chuyển.

Đây là một bài viết tuyệt vời giải thích kịch bản này; http://www.johandekaming.nl/index.php/2013/03/03/dont-wrap-your-ioc-container/


Liên kết bài viết johandekizing bị hỏng.
JakeJ

6

Tôi nghĩ rằng hai người làm việc cùng nhau.

Việc tiêm phụ thuộc có nghĩa là bạn đẩy một số lớp / giao diện phụ thuộc vào một lớp tiêu thụ (thường là cho hàm tạo của nó). Điều này tách riêng hai lớp thông qua một giao diện và có nghĩa là lớp tiêu thụ có thể hoạt động với nhiều kiểu triển khai "phụ thuộc được tiêm".

Vai trò của trình định vị dịch vụ là kết hợp việc thực hiện của bạn. Bạn thiết lập một bộ định vị dịch vụ thông qua một số đóng đai khởi động khi bắt đầu chương trình của bạn. Bootstrapping là quá trình liên kết một kiểu thực hiện với một giao diện / trừu tượng cụ thể. Mà được tạo ra cho bạn trong thời gian chạy. (dựa trên bạn cấu hình hoặc bootstrap). Nếu bạn chưa thực hiện tiêm phụ thuộc, sẽ rất khó sử dụng bộ định vị dịch vụ hoặc bộ chứa IOC.


6

Một lý do để thêm, lấy cảm hứng từ một bản cập nhật tài liệu mà chúng tôi đã viết cho dự án MEF tuần trước (tôi giúp xây dựng MEF).

Khi một ứng dụng được tạo thành từ hàng ngàn thành phần tiềm năng, có thể khó xác định liệu bất kỳ thành phần cụ thể nào có thể được khởi tạo chính xác hay không. Bằng cách "khởi tạo chính xác", ý tôi là trong ví dụ này dựa trên Foothành phần, một thể hiện IBarvà sẽ có sẵn, và thành phần cung cấp nó sẽ:

  • có phụ thuộc cần thiết của nó,
  • không được tham gia vào bất kỳ chu kỳ phụ thuộc không hợp lệ nào và
  • trong trường hợp MEF, chỉ được cung cấp một trường hợp.

Trong ví dụ thứ hai mà bạn đã đưa ra, nơi nhà xây dựng đi đến bộ chứa IoC để truy xuất các phụ thuộc của nó, cách duy nhất mà bạn có thể kiểm tra rằng một cá thể Foosẽ có thể được khởi tạo chính xác với cấu hình thời gian chạy thực tế của ứng dụng của bạnthực sự xây dựng nó .

Điều này có tất cả các loại tác dụng phụ khó xử tại thời điểm thử nghiệm, bởi vì mã sẽ hoạt động trong thời gian chạy sẽ không nhất thiết phải hoạt động theo khai thác thử nghiệm. Mocks sẽ không làm được, bởi vì cấu hình thực sự là thứ chúng ta cần kiểm tra chứ không phải thiết lập thời gian thử nghiệm.

Nguyên nhân của vấn đề này là sự khác biệt đã được gọi ra bởi @Jon: tiêm phụ thuộc thông qua hàm tạo là khai báo, trong khi phiên bản thứ hai sử dụng mẫu Định vị dịch vụ bắt buộc.

Một bộ chứa IoC, khi được sử dụng cẩn thận, có thể phân tích tĩnh cấu hình thời gian chạy của ứng dụng của bạn mà không thực sự tạo ra bất kỳ trường hợp nào của các thành phần liên quan. Nhiều container phổ biến cung cấp một số biến thể của điều này; Microsoft.Cysis , phiên bản của MEF nhắm mục tiêu ứng dụng web và web .NET 4.5, cung cấp một CompositionAssertmẫu trong tài liệu wiki. Sử dụng nó, bạn có thể viết mã như:

 // Whatever you use at runtime to configure the container
var container = CreateContainer();

CompositionAssert.CanExportSingle<Foo>(container);

(Xem ví dụ này ).

Bằng cách xác minh Rễ thành phần của ứng dụng của bạn tại thời điểm kiểm tra, bạn có khả năng có thể mắc một số lỗi có thể xảy ra trong quá trình kiểm tra sau này trong quy trình.

Hy vọng đây là một bổ sung thú vị cho bộ câu trả lời toàn diện này về chủ đề này!


5

Lưu ý: Tôi không trả lời chính xác câu hỏi. Nhưng tôi cảm thấy rằng điều này có thể hữu ích cho những người mới học về mẫu Tiêm phụ thuộc, những người bối rối về nó với mẫu Trình định vị dịch vụ (chống) tình cờ tình cờ gặp phải trang này.

Tôi biết sự khác biệt giữa Trình định vị dịch vụ (dường như được coi là kiểu chống mẫu bây giờ) và các mẫu Tiêm phụ thuộc và có thể hiểu các ví dụ cụ thể từng mẫu, nhưng tôi đã nhầm lẫn với các ví dụ hiển thị trình định vị dịch vụ bên trong hàm tạo (giả sử chúng tôi ' đang thực hiện tiêm xây dựng).

"Bộ định vị dịch vụ" thường được sử dụng cả làm tên của mẫu và làm tên để chỉ đối tượng (giả sử) được sử dụng trong mẫu đó để lấy các đối tượng mà không cần sử dụng toán tử mới. Bây giờ, cùng loại đối tượng đó cũng có thể được sử dụng ở gốc thành phần để thực hiện tiêm phụ thuộc và đó là nơi gây ra sự nhầm lẫn.

Vấn đề cần lưu ý là bạn có thể đang sử dụng một đối tượng định vị dịch vụ bên trong hàm tạo DI, nhưng bạn không sử dụng "mẫu Định vị dịch vụ". Thay vào đó, sẽ ít gây nhầm lẫn hơn nếu người ta coi nó là một đối tượng chứa IoC, vì bạn có thể đoán rằng về cơ bản họ cũng làm điều tương tự (hãy sửa tôi nếu tôi sai).

Cho dù nó được gọi là công cụ định vị dịch vụ (hoặc chỉ là công cụ định vị) hoặc là công cụ chứa IoC (hoặc chỉ là công cụ chứa) không có gì khác biệt như bạn đoán vì có lẽ chúng đang đề cập đến cùng một sự trừu tượng hóa (hãy sửa cho tôi nếu tôi sai ). Chỉ cần gọi nó là một trình định vị dịch vụ cho thấy rằng một người đang sử dụng mô hình chống Định vị dịch vụ cùng với mẫu Tiêm phụ thuộc.

IMHO, đặt tên cho nó là 'trình định vị' thay vì 'vị trí' hoặc 'định vị', đôi khi cũng có thể khiến người ta nghĩ rằng trình định vị dịch vụ trong một bài viết đang đề cập đến bộ chứa Định vị dịch vụ chứ không phải mẫu Định vị dịch vụ (chống) , đặc biệt là khi có một mô hình liên quan được gọi là Dependency Injection và không phải Dependency Injection.


4

Trong trường hợp đơn giản hóa này, không có sự khác biệt và chúng có thể được sử dụng thay thế cho nhau. Tuy nhiên, các vấn đề trong thế giới thực không đơn giản. Chỉ cần giả sử rằng chính lớp Bar có một phụ thuộc khác có tên D. Trong trường hợp đó, trình định vị dịch vụ của bạn sẽ không thể giải quyết sự phụ thuộc đó và bạn sẽ phải khởi tạo nó trong lớp D; bởi vì đó là trách nhiệm của các lớp học của bạn để khởi tạo sự phụ thuộc của họ. Nó thậm chí còn trở nên tồi tệ hơn nếu bản thân lớp D có các phụ thuộc khác và trong các tình huống thực tế, nó thường còn phức tạp hơn thế. Trong các trường hợp như vậy, DI là một giải pháp tốt hơn ServiceLocator.


4
Hmm tôi không đồng ý: công cụ định vị dịch vụ cũ. rõ ràng cho thấy rằng vẫn còn một sự phụ thuộc ở đó ... công cụ định vị dịch vụ. Nếu barbản thân lớp đó có một phụ thuộc, thì barcũng sẽ có bộ định vị dịch vụ, đó là toàn bộ quan điểm của việc sử dụng DI / IoC.
GFoley83

2

Sự khác biệt (nếu có) giữa Phụ thuộc dịch vụ tiêm và Định vị dịch vụ là gì? Cả hai mô hình đều tốt trong việc thực hiện nguyên tắc Nghịch đảo phụ thuộc. Mẫu Trình định vị dịch vụ dễ sử dụng hơn trong một cơ sở mã hiện có vì nó làm cho thiết kế tổng thể lỏng hơn mà không buộc thay đổi giao diện chung. Vì lý do tương tự, mã dựa trên mẫu Trình định vị dịch vụ ít đọc hơn mã tương đương dựa trên Tiêm phụ thuộc.

Mẫu Dependency Injection cho thấy rõ vì chữ ký phụ thuộc vào một lớp (hoặc một phương thức) sẽ có. Vì lý do này, mã kết quả là sạch hơn và dễ đọc hơn.


1

Theo quan niệm đơn giản đã cho tôi hiểu rõ hơn về sự khác biệt giữa Bộ định vị dịch vụ và DI Container:

  • Trình định vị dịch vụ được sử dụng trong người tiêu dùng và nó lấy các dịch vụ bằng ID từ một số lưu trữ theo yêu cầu của người tiêu dùng trực tiếp

  • DI Container được đặt ở đâu đó bên ngoài và nó lấy dịch vụ từ một số bộ lưu trữ và đẩy chúng đến người tiêu dùng (không có vấn đề thông qua phương thức xây dựng hoặc thông qua phương thức)

Tuy nhiên, chúng ta có thể nói về sự khác biệt giữa những điều này chỉ trong bối cảnh sử dụng cụ thể của người tiêu dùng. Khi Bộ định vị dịch vụ và DI Container được sử dụng trong gốc thành phần, chúng gần như tương tự nhau.


0

DI container là một siêu bộ định vị dịch vụ. Nó có thể được sử dụng để định vị một dịch vụ , với khả năng bổ sung lắp ráp (nối dây) các mũi tiêm phụ thuộc .


-2

Đối với hồ sơ

//Foo Needs an IBar
public class Foo
{
  private IBar bar;

  public Foo(IBar bar)
  {
    this.bar = bar;
  }

  //...
}

Trừ khi bạn thực sự cần một giao diện (giao diện được sử dụng bởi nhiều hơn một lớp), bạn KHÔNG PHẢI SỬ DỤNG CNTT . Trong trường hợp này, IBar cho phép sử dụng bất kỳ lớp dịch vụ nào, thực hiện nó. Tuy nhiên, thông thường, Giao diện này sẽ được sử dụng bởi một lớp duy nhất.

Tại sao nó là một ý tưởng tồi để sử dụng một giao diện?. Bởi vì nó thực sự khó để gỡ lỗi.

Ví dụ: giả sử rằng "thanh" thể hiện không thành công, câu hỏi: lớp nào thất bại?. Tôi nên sửa mã nào? Một cái nhìn đơn giản, nó dẫn đến một Giao diện, và đây là nơi con đường của tôi kết thúc.

Thay vào đó, nếu mã sử dụng một phụ thuộc cứng thì dễ dàng gỡ lỗi.

//Foo Needs an IBar
public class Foo
{
  private BarService bar;

  public Foo(IBar bar)
  {
    this.bar = bar;
  }

  //...
}

Nếu "thanh" không thành công, thì tôi nên kiểm tra và sử dụng lớp BarService.


1
Một lớp là một kế hoạch chi tiết để xây dựng đối tượng cụ thể. Mặt khác, một giao diện là một contractvà chỉ định nghĩa một hành vi không phải là hành động. Thay vì chuyển xung quanh đối tượng thực tế, chỉ có giao diện được chia sẻ để người tiêu dùng không truy cập vào phần còn lại của đối tượng của bạn. Ngoài ra để kiểm tra đơn vị, nó chỉ giúp kiểm tra phần cần kiểm tra. Tôi đoán trong thời gian bạn hiểu sự hữu ích của nó.
Gunhan
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.