2010-10-15 14 views
7

Tôi đang cố gắng giới thiệu DI (với Autofac) vào một ứng dụng Windows Forms hiện có.DI (Autofac) trong kiến ​​trúc plugin: Có phải một vùng chứa DI riêng biệt cho mỗi trình cắm thêm OK không?

Ứng dụng này có kiến ​​trúc trình cắm cơ bản trong đó mỗi plugin hiển thị biểu mẫu riêng. Khi khởi động, quét ứng dụng đăng ký lắp ráp với nhiều loại mà thực hiện IPlugin, và sau đó kích hoạt những sử dụng Activator.CreateInstance:

public interface IPlugin 
{ 
    Form MainForm { get; } 
} 

tôi không thể thay đổi khuôn khổ cho này. Điều này có nghĩa, mỗi lớp plugin được khởi tạo thông qua các phương tiện không phải DI, và có vẻ như với tôi rằng tôi sẽ phải khởi động một vùng chứa DI riêng biệt cho mỗi plugin.

Câu hỏi của tôi là, đang tạo riêng ContainerBuilder và vùng chứa cho mỗi plugin OK và vẫn hợp lý hiệu quả? (Sẽ có khoảng 10 plugin khác nhau.) Hoặc chỉ nên có một vùng chứa DI cho toàn bộ ứng dụng?

Tôi đã cung cấp một số mã mẫu của giải pháp hiện tại của mình bên dưới.


using Autofac; 
using System.Windows.Forms; 

public class Plugin : IPlugin // instantiated by Activator 
{ 
    public Form MainForm { get; private set; } 

    public Plugin() // parameter-less constructor required by plugin framework 
    { 
     var builder = new ContainerBuilder(); 
     builder.RegisterModule(new Configuration()); 
     var container = builder.Build(); 

     MainForm = container.Resolve<MainForm>(); 
     //^preferred to new MainForm(...) because this way, I can take 
     // advantage of having dependencies auto-wired by the container. 
    } 
} 

internal class Configuration : Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
     builder.RegisterType<MainForm>().SingleInstance(); 
     // ... more plugin-specific registrations go here... 
    } 
} 

internal class MainForm : Form { /* ... */ } 

Tôi cũng không chắc liệu tạo vùng chứa trong các nhà xây dựng plugin và sau đó chỉ cần quên về nó, nhưng để lại nó để làm tự động hệ thống dây điện ở chế độ nền, là OK?

Trả lời

7

Việc sử dụng vùng chứa của bạn nên lý tưởng theo dõi Register Resolve Release pattern (RRR). Tôi biết rằng bạn đã nói rằng bạn không thể thay đổi việc sử dụng Activator.CreateInstance hiện tại, nhưng nó vẫn có thể hữu ích để hiểu nó thực sự nên như thế nào.

Nếu bạn không có ràng buộc đó, chỉ nên có một phiên bản vùng chứa duy nhất, được lưu trữ bởi chính ứng dụng gốc. Điều này sau đó có thể được sử dụng để soạn tất cả các plugin. Điều này sẽ cho phép các plugin chia sẻ các phụ thuộc. Đây là tuyến đường được thực hiện bởi MEF, cũng giải quyết các kịch bản mở rộng.

Bây giờ, vì bạn không thể làm điều đó, điều tốt nhất tiếp theo bạn có thể làm là có một vùng chứa cho mỗi plugin như bạn đề xuất. Nó chủ yếu trở thành một chi tiết thực hiện tại thời điểm đó. Trong mỗi plugin, bạn vẫn nên làm theo mẫu RRR.

Nó sẽ không hiệu quả? Trừ khi bạn có rất nhiều plugin và tạo ra và tiêu diệt chúng tất cả các thời gian, một vài container khác nhau không nên quan trọng nhiều. Tuy nhiên, tốt hơn là đo lường hơn để tạo tối ưu hóa sớm.

Trong trường hợp này, bạn chỉ có thể chia sẻ vùng chứa bằng cách đặt vùng chứa tĩnh. Tuy nhiên, điều này làm cho mọi việc trở nên phức tạp hơn những gì họ cần, vì vậy đừng đi theo con đường đó trừ khi thật sự cần thiết.

+0

Cảm ơn bạn đã trả lời, @Mark. Nếu tôi hiểu bạn một cách chính xác, mã ví dụ của tôi đã tuân theo mẫu RRR ... đúng không? (Ngoại trừ việc tôi không giải phóng container, vì nó cần phải sống sót ít nhất miễn là thành phần gốc 'MainForm'. Tôi cho rằng, cách lý tưởng để làm điều này là tạo các plugin' IDisposable' và phát hành các thùng chứa trong phương pháp 'Dispose'.) – stakx

+2

Không có gì trong mã của bạn cho thấy rằng bạn không theo RRR, nhưng thật khó để nói. Trong mọi trường hợp, hãy nhớ rằng lối sống SingleInstance chỉ định nghĩa một Singleton chứa phạm vi chứa. Nó không phải là Singleton thực sự, vì vậy bạn không thể chia sẻ MainForm theo cách này. –

0

Tôi cũng không chắc liệu tạo vùng chứa trong trình tạo plugin và sau đó chỉ đơn giản là quên nó, nhưng để nó tự động kết nối ở chế độ nền, OK?

Nhìn vào câu hỏi của riêng tôi nhiều tháng sau đó, tôi dám nói rằng chỉ cần quên container không phải là OK, vì (a) nó là IDisposable và cần được đối xử như vậy, và (b) kiếp một số thành phần bị ràng buộc vào container, do đó tuổi thọ của container phải được kết thúc rõ ràng; có thể là phương thức Dispose của biểu mẫu hoặc khi sự kiện FormClosed của nó được kích hoạt.

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