2012-01-31 15 views
7

Dường như có sự kỳ thị về SO liên quan đến việc sử dụng Singletons. Tôi đã không bao giờ cá nhân mua vào nó, nhưng vì lợi ích cởi mở cởi mở, tôi đang cố gắng để cung cấp cho các khái niệm IoC một thử là một thay thế bởi vì tôi thẳng thắn chán với công việc hàng ngày của tôi và muốn thử một cái gì đó khác nhau. Tha thứ cho tôi nếu diễn giải của tôi về khái niệm IoC là không đúng hoặc sai lầm.Lợi ích của IoC đối với Nhà máy của tôi Singleton

Đây là tình huống: Tôi đang xây dựng một máy chủ web đơn giản HttpListener dựa trên cửa sổ sử dụng mô hình trình cắm để xác định cách xử lý yêu cầu dựa trên URL được yêu cầu (giống như mọi người khác hỏi về HttpListener). Cách tiếp cận của tôi để khám phá các trình cắm thêm là truy vấn một thư mục được cấu hình cho các assembly được trang trí với một HttpModuleAssemblyAttribute. Những hội đồng này có thể chứa 0 hoặc nhiều hơn IHttpModule trẻ em ngoài ra được trang trí với HttpModuleAttribute được sử dụng để chỉ định tên, phiên bản, mô tả có thể đọc được của con người và nhiều thông tin khác. Một cái gì đó như:

[HttpModule(/*Some property values that matter */)] 
public class SimpleHttpModule : IHttpModule 
{ 
    public void Execute(HttpListenerContext context) 
    { 
     /* Do Something Special */ 
    } 
} 

Khi một HttpModule được phát hiện tôi thường sẽ thêm nó vào một đối tượng Dictionary<string, Type> người là mục đích duy nhất là để theo dõi những mô-đun chúng ta biết về. Từ điển này thường sẽ sống trong một loạt các Singleton của tôi mà mất trên persona của một ACE style Singleton (một di sản từ ngày C++ của tôi, nơi tôi đã học được về Singletons).

Bây giờ những gì tôi đang cố gắng thực hiện là một cái gì đó tương tự bằng cách sử dụng (hiểu biết của tôi về) khái niệm chung của IoC. Về cơ bản những gì tôi có là một AppService bộ sưu tập nơi IAppService được định nghĩa là:

public interface IAppService : IDisposable 
{ 
    void Initialize(); 
} 

Và tôi plug-in AppService sẽ giống như thế:

[AppService("Plugins")] 
internal class PluginAppService : IAppService, IDictionary<string, Type> 
{ 
    /* Common IDictionary Implementation consisting of something like: */ 
    internal Type Item(string modName) 
    { 
     Type modType; 
     if (!this.TryGetValue(modName, out modType) 
      return null; 

     return modType; 
    } 

    internal void Initialize() 
    { 
     // Find internal and external plug-ins and add them to myself 
    } 

    // IDisposable clean up method that attempts to dispose all known plug-ins 
} 

Sau đó, trong quá trình dịch vụ OnStart tôi nhanh chóng một thể hiện của AppServices mà được biết tại địa phương nhưng được truyền cho nhà xây dựng của tất cả các trình cắm được khởi tạo:

public class AppServices : IDisposable, IDictionary<string, IAppService> 
{ 
    /* Simple implementation of IDictionary */ 

    public void Initialization() 
    { 
     // Find internal IAppService implementations, instantiate them (passing this as a constructor parameter), initialize them and add them to this. 

     // Somewhere in there would be something like 
     Add(appSvcName, appSvc); 
    } 
} 

chúng tôi phương pháp một lần duy nhất thực hiện trở thành một thực hiện trừu tượng + một constructor trên con:

[HttpModule(/*Some property values that matter */)] 
public abstract class HttpModule : IHttpModule 
{ 
    protected AppServices appServices = null; 
    public HttpModule(AppServices services) 
    { 
     appServices = services; 
    }    

    public abstract void Execute(HttpListenerContext context); 
} 

[HttpModule(/*Some property values that matter */)] 
public class SimpleHttpModule : HttpModule 
{ 
    public SimpleHttpModule(AppServices services) : base(services) { } 
    public override void Execute(HttpListenerContext context) 
    { 
     /* Do Something Special */ 
    } 
} 

Và bất kỳ quyền truy cập vào các dịch vụ ứng dụng thường được sử dụng trở thành:

var plugType = appServices["Plugins"][plugName]; 

hơn:

var plugType = PluginManager.Instance[plugName]; 

Tôi có thiếu một số khái niệm cơ bản của IoC ở đây để đơn giản hóa tất cả hoặc có thực sự là một lợi ích cho tất cả các mã bổ sung này? Trong thế giới của tôi, Singletons là những sinh vật đơn giản cho phép mã trong suốt một chương trình truy cập thông tin cần thiết (tương đối tĩnh) (trong trường hợp này là các loại).

Để đặt ra các câu hỏi một cách rõ ràng hơn:

  1. Đây có phải là một việc thực hiện hợp lệ của một Singleton Factory dịch sang khái niệm IoC/DI?
  2. Nếu có, đâu là hoàn vốn/lợi ích cho mã bổ sung được yêu cầu và áp dụng API có vẻ phức tạp hơn?
+0

Có thể bạn không nhận được câu trả lời mà bạn đang tìm kiếm vì câu hỏi của bạn quá mơ hồ (mặc dù quá dài). Bạn nên thực sự hình chính xác câu hỏi nào bạn muốn trả lời và hỏi nó. –

+0

Tôi nghĩ rằng phản ứng dữ dội chung đối với các single là do chúng là một phương thức giới thiệu trạng thái toàn cầu vào một ứng dụng, chạy ngược với thiết kế hướng đối tượng. Họ cũng thường xuyên khó kiểm tra đơn vị. –

+0

@DBM - Trạng thái toàn cầu phản đối OOP? Làm thế nào? Nó thường là một cách tiếp cận được chấp nhận trong C++ (cũng là OO). –

Trả lời

1

Trong khi tôi vẫn chưa thực sự tin rằng IoC/DI là tốt hơn trong tình huống này, tôi chắc chắn đã thấy được lợi ích khi phạm vi của dự án len lỏi. Đối với những thứ như đăng nhập và cấu hình nó chắc chắn nhất là cách tiếp cận đúng.

Tôi mong muốn thử nghiệm nhiều hơn trong các dự án trong tương lai.

1

IoC trở nên thú vị hơn khi bạn làm tròn để viết các bài kiểm tra đơn vị. Xin lỗi để trả lời câu hỏi có nhiều câu hỏi hơn, nhưng ... Các bài kiểm tra đơn vị sẽ trông như thế nào cho cả hai triển khai của bạn? Bạn sẽ có thể đơn vị kiểm tra các lớp học sử dụng PluginManager mà không cần nhìn lên cụm từ đĩa?

EDIT

Chỉ vì bạn có thể đạt được các chức năng tương tự với độc thân không có nghĩa là nó dễ dàng để duy trì. Bằng cách sử dụng IoC (ít nhất là kiểu này với các hàm tạo), bạn rõ ràng nói rõ các phụ thuộc mà một đối tượng có. Bằng cách sử dụng singletons rằng thông tin được ẩn trong lớp. Nó cũng làm cho nó khó khăn hơn để thay thế những phụ thuộc với việc triển khai thay thế.

Vì vậy, với một singleton PluginManager sẽ rất khó để kiểm tra máy chủ HTTP của bạn với các plugin giả, thay vì tìm kiếm chúng từ một số vị trí trên đĩa. Với phiên bản IoC, bạn có thể chuyển xung quanh một phiên bản thay thế của IAppService mà chỉ cần tìm các plugin từ một số tiền được điền trước là Dictionary.

+0

Dựa trên bản chất của một khung công cụ plug-in (thậm chí cụ thể hơn là cái mà tôi đã định nghĩa ở đây), các mocks rất dễ thực hiện vì chúng chỉ phải được trang trí với một 'HttpModuleAttribute' có cùng tên và thực hiện giao diện.Khuôn khổ là không biết gì ngoài điều đó. Thực tế cả hai cách triển khai đều chỉ ra các phụ thuộc vì chúng thực thi cả yêu cầu 'IHttpModule' hoặc' HttpModule' được thực thi. Có thể nhiều ví dụ cụ thể hơn về thiếu sót sẽ giúp ích cho bạn. –

+0

Điều gì sử dụng 'PluginManager'? Đó là nơi bạn sẽ thấy sự khác biệt IMHO. – SimonC

+0

Bản thân khung công tác sử dụng 'PluginManager' tùy thuộc vào URL nhận được. 'http: // server.com/moduleName/someFile.txt' sẽ là một cái gì đó được tiêu thụ bởi framework và' moduleName' sẽ là tên của module được đăng ký với một trong hai 'PluginManager' hoặc' PluginAppService'. Dù bằng cách nào thì sự tương tác của nó với nó là như nhau. –

2

IoC là một thuật ngữ chung. Dependency Injection là thuật ngữ được ưa thích nhiều hơn trong những ngày này.

Tiêm phụ thuộc thực sự tỏa sáng trong một số trường hợp. Đầu tiên, nó định nghĩa một kiến ​​trúc có thể thử nghiệm hơn các giải pháp có các sự phụ thuộc mã hóa cứng của các phụ thuộc. Singletons khó kiểm tra đơn vị vì chúng là tĩnh, và dữ liệu tĩnh không thể được "unloaded".

Thứ hai, Dependency Injection không chỉ instantiates loại bạn muốn, nhưng tất cả các loại phụ thuộc. Do đó, nếu lớp A cần lớp B và lớp B cần lớp C và D, thì khung DI tốt sẽ tự động tạo tất cả các phụ thuộc và kiểm soát thời gian sống của chúng (ví dụ, làm cho chúng tồn tại suốt đời của một yêu cầu web).

DI Vùng chứa có thể là các nhà máy chung có thể khởi tạo bất kỳ loại đối tượng nào (miễn là được cấu hình đúng và đáp ứng mọi yêu cầu của khung DI). Vì vậy, bạn không phải viết một nhà máy tùy chỉnh.

Giống như với bất kỳ giải pháp chung nào, nó được thiết kế để cung cấp cho 90% trường hợp sử dụng những gì họ cần. Chắc chắn, bạn có thể tạo cấu trúc dữ liệu danh sách được liên kết tùy chỉnh thủ công mỗi lần bạn cần một bộ sưu tập, nhưng 90 =% thời gian một bộ sưu tập chung sẽ hoạt động tốt. Điều này cũng đúng với DI và Nhà máy tùy chỉnh.

+0

Tôi đánh giá cao thông tin chi tiết, mặc dù tôi nhầm lẫn về cách áp dụng cho các trường hợp được chỉ định trong câu hỏi? Tôi đã đọc các bài viết về Dependency Injection và Inversion of Control, nhưng tôi đã sử dụng mô hình này qua các ngôn ngữ với các trải nghiệm kiểm tra đơn vị tích cực. Tại sao chuyển đổi ngay bây giờ? –

+0

Đặt khác, điều gì về kịch bản được mô tả của tôi khiến DI trở thành lựa chọn tốt hơn? Tôi có thiếu khái niệm? –

+1

Cũng cần lưu ý rằng có sự khác biệt giữa Inversion of Control (IoC) và Dependency Injection (DI), http://stackoverflow.com/questions/4596300/where-exactly-is-the-difference-between-ioc -and-di –