2008-12-14 57 views
28

Tôi nghĩ câu trả lời cho câu hỏi này thật đáng ghét đến nỗi không ai có bận tâm về vấn đề này, nhưng muộn rồi và tôi thực sự không thể xoay sở được điều này.Cách sử dụng Thùng chứa IoC; Cụ thể là Windsor

Tôi đã đọc vào các thùng chứa IoC (Windsor trong trường hợp này) và tôi đang thiếu cách bạn nói chuyện với vùng chứa từ các phần khác nhau của mã của bạn.

Tôi nhận được DI, tôi đã làm những người nghèo DI (các nhà thầu trống gọi các nhà thầu phun quá tải với các triển khai tham số mặc định) trong một thời gian và tôi hoàn toàn có thể thấy lợi ích của container. Tuy nhiên, Im thiếu một phần quan trọng của thông tin; làm thế nào bạn có nghĩa vụ phải tham khảo các container mỗi khi bạn cần một dịch vụ từ nó?

Tôi có tạo ra một tài liệu toàn cầu duy nhất mà tôi vượt qua không? Chắc chắn là không!

Tôi biết tôi nên gọi đây là:

WindsorContainer container = new WindsorContainer(new XmlInterpreter()); 

(ví dụ) khi tôi muốn tải cấu hình XML của tôi, nhưng sau đó tôi phải làm gì với container? Không tạo ra một container mới mỗi lần sau đó vẫn duy trì cấu hình được tải thông qua một số chuyên ngành tĩnh nội bộ hoặc cách khác, hoặc tôi phải tải lại cấu hình mỗi lần (tôi đoán không, hoặc vòng đời không thể làm việc).

Không hiểu điều này là ngăn chặn tôi từ làm việc hiểu cách thức vòng đời làm việc, và nhận được trên với việc sử dụng một số IoC awsomeness

Cảm ơn,

Andrew

Trả lời

24

99% trường hợp là một phiên bản vùng chứa cho mỗi ứng dụng. Thông thường bạn khởi tạo nó trong Application_Start (cho một ứng dụng web), like this.

Sau đó, điều đó thực sự phụ thuộc vào người tiêu dùng của vùng chứa. Ví dụ, một số khung công tác, như MonorailASP.NET MVC cho phép bạn chặn việc tạo ra các cá thể (các trình điều khiển trong trường hợp này), vì vậy bạn chỉ cần đăng ký bộ điều khiển và phụ thuộc của chúng trong vùng chứa đó và bất cứ khi nào bạn nhận được yêu cầu chăm sóc tiêm mỗi bộ điều khiển với các phụ thuộc của nó. Xem ví dụ this ASP.NET MVC controller. Trong các khung công tác này, bạn hầu như không bao giờ cần phải gọi hoặc thậm chí tham khảo vùng chứa trong các lớp học của bạn, đó là cách sử dụng được khuyến nghị.

khuôn khổ khác đừng để bạn nhận được trong quá trình tạo một cách dễ dàng (như Webforms), do đó bạn phải nghỉ mát để hacks như this one, hoặc kéo sự phụ thuộc yêu cầu (có nghĩa là, gọi một cách rõ ràng container). Để kéo phụ thuộc, hãy sử dụng cổng tĩnh vào vùng chứa như this one hoặc cổng được mô tả bởi maxnk. Lưu ý rằng bằng cách làm điều này, bạn đang thực sự sử dụng các container như là một Service Locator, mà không decouple những thứ cũng như đảo ngược kiểm soát.(xem sự khác biệt herehere)

Hy vọng điều này sẽ làm rõ những nghi ngờ của bạn.

+0

Thực ra, rất nhiều môi trường có một lớp "root toàn cầu" ở đâu đó, nếu bạn tìm nó. Silverlight và WPF có lớp ứng dụng (code-behind cho App.xaml), đây là nơi tốt để neo một container IOC. Đối với WPF và Silverlight lớn hơn, bạn chắc chắn muốn xem Prism, cung cấp cả hai công cụ cấu trúc quy mô lớn và Unity, đó là container IOC của MS. –

+0

@Cylon: và ASP.NET có Application_Start(), nhưng điều đó không có nghĩa là nó sẽ cho phép bạn chặn việc tạo đối tượng. Nó chỉ có nghĩa là bạn có một nơi để thiết lập các container. –

+0

Tạo trang ASP.NET WebForms có thể bị chặn và Pages bằng cách 'xây dựng' cho DI bằng cách tạo PageHandlerFactory và đăng ký triển khai trong web.config. Xem http://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=81#comm –

0

Tôi đang sử dụng một thực hiện điều này giao diện:

public interface IResolver 
{ 
    object Resolve(Type type); 
    object Resolve(string name); 

    T Resolve<T>() where T : class; 
    T Resolve<T>(string name) where T : class; 
} 

Thực tế được gói trong lớp tĩnh toàn cầu, ví dụ:

public static class Resolver // : IResolver 
{ 
    private static IResolver _current; 

    public static object Resolve(Type type) 
    { 
     return Current.Resolve(type); 
    } 

    public static object Resolve(string name) 
    { 
     return Current.Resolve(name); 
    } 

    public static T Resolve<T>() where T : class 
    { 
     return Current.Resolve<T>(); 
    } 

    public static T Resolve<T>(string name) where T : class 
    { 
     return Current.Resolve<T>(name); 
    } 

    private static IResolver Current 
    { 
     get 
     { 
      if (_current == null) 
      { 
       _current = new SpringResolver(); 
      } 

      return _current; 
     } 
    } 
} 

Ngoài ra tôi đang cố gắng tuân theo quy tắc đơn giản - sử dụng lớp Resolver càng ít càng tốt, thay vào đó tiêm dịch vụ vào các đối tượng cần các dịch vụ đó.

+4

-1 để đề xuất bộ định vị dịch vụ. –

+0

Tuy nhiên (tôi nhận ra mình đã trễ trò chơi ở đây), nếu thay vì có Resolver là một lớp tĩnh toàn cục, và bạn chuyển nó thành một đối số được tiêm vào các đối tượng cần tạo các đối tượng của riêng mình thì nó sẽ trở thành một Abstract Factory , đó là một điều tốt hơn so với một định vị dịch vụ, phải không? –

3

Thông thường bạn chỉ muốn giữ một phiên bản trong toàn bộ thời gian của toàn bộ ứng dụng. Những gì tôi làm hầu hết thời gian là tôi khởi tạo các container khi ứng dụng bắt đầu, và sau đó tôi sử dụng các nhà máy đánh máy cho container-không biết kéo đối tượng.

Cách tiếp cận phổ biến khác là bọc cá thể vùng chứa với lớp tĩnh và sử dụng lớp tĩnh đó để truy cập vùng chứa (singleton) của bạn. Bạn có thể tìm thấy một ví dụ về điều đó trong thư viện Rhino.Commons của Ayende here. Tuy nhiên, cách tiếp cận này có những hạn chế nghiêm trọng và cần tránh.

+0

"Những gì tôi làm hầu hết thời gian là tôi khởi tạo các container khi ứng dụng bắt đầu, và sau đó tôi vượt qua nó xung quanh cho những người cần nó." Tôi thích ý tưởng này.Bạn có nghĩ rằng bạn có thể cung cấp một liên kết hoặc mẫu? –

+1

Hãy xem tài liệu của Windsor –

1

Như các câu trả lời khác ở đây, có rất nhiều lựa chọn, và một lần nữa chúng tôi để lại cho chính mình để tìm ra điều tốt nhất trong trường hợp của chúng tôi.

Điều đó nói rằng, IMO có một container toàn cầu được truy cập trong suốt ứng dụng của bạn phần nào phá vỡ sự cô lập trong đó rất nhiều mã bây giờ phụ thuộc vào một lớp toàn cầu. Ngoài ra, đối với các ứng dụng được tách ra thành một số cụm, thùng chứa toàn cục phải được truy cập cho tất cả các assembly này.

Với Unity bạn thực sự có thể có tham số IUnityContainer trong hàm tạo của bạn và vùng chứa sẽ tự động tự chèn vào cá thể khi bạn giải quyết lớp. Bằng cách này, đối với các dịch vụ cần giải quyết các dịch vụ khác mà bạn chuyển vào vùng chứa thay vì buộc lớp tham chiếu lớp bên ngoài.

Không chắc chắn các khung công tác khác hỗ trợ kịch bản này như thế nào (Windsor sẽ tiêm IKernel).

+2

"đối với các ứng dụng được chia thành nhiều cụm, container toàn cầu phải được tiếp cận với tất cả các cụm này." Không, một trong những điểm chính của bất kỳ container IoC nào là không xâm phạm. Windsor và những người khác đạt được và đề nghị điều đó. –

+0

@mausch - _how_ hiện nó đạt được điều đó, khi có vẻ là một khuyến cáo chung để có một thùng chứa singleton được chia sẻ? Hay tôi sai trong giả định này? Tôi không thấy câu trả lời của tôi mâu thuẫn với các điểm IoC như thế nào. Nó chỉ là cách mà người ta sử dụng các khung công tác IoC, chứ không phải các khung công tác, mà cảm thấy xâm nhập. –

+1

Có, có một thùng chứa duy nhất, nhưng không ai biết về nó ngoại trừ mã khởi động và một số mã keo cụ thể (ví dụ: ASP.NET MVC ControllerFactory như http://mvccontrib.googlecode.com/svn/trunk/src/ MvcContrib.Castle/WindsorControllerFactory.cs). –

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