Nói chung, hầu hết các phụ thuộc có thể được đưa vào lớp học của bạn tại thời điểm được tạo. Tuy nhiên, trong trường hợp cụ thể này, bạn cần một thành phần phải được tạo theo yêu cầu tại thời điểm sử dụng. Trong những trường hợp như vậy, rất khó để loại bỏ hoàn toàn sự phụ thuộc vào một thùng chứa IoC. Cách tiếp cận của tôi luôn luôn là tạo ra một nhà máy được tiêm vào lớp tại thời điểm tạo ra, do đó đóng gói tất cả việc sử dụng IoC trực tiếp. Điều này cho phép các nhà máy của bạn để nhạo báng để thử nghiệm, chứ không phải là container IoC bản thân ... mà có xu hướng được dễ dàng hơn rất nhiều:
// In Presentation.csproj
class PresentationController
{
public PresentationController(IDataContextFactory dataContextFactory, IRepositoryFactory repositoryFactory)
{
#region .NET 4 Contract
Contract.Requires(dataContextFactory != null);
Contract.Requires(repositoryFactory != null);
#endregion
_dataContextFactory = dataContextFactory;
_repositoryFactory = repositoryFactory;
}
private readonly IDataContextFactory _dataContextFactory;
private readonly IRepositoryFactory _repositoryFactory;
public void Action()
{
using (IDataContext dc = _dataContextFactory.CreateInstance())
{
var repo = _repositoryFactory.CreateUserRepository();
// do stuff with repo...
}
}
}
// In Factories.API.csproj
interface IDataContextFactory
{
IDataContext CreateInstance();
}
interface IRepositoryFactory
{
IUserRepository CreateUserRepository();
IAddressRepository CreateAddressRepository();
// etc.
}
// In Factories.Impl.csproj
class DataContextFactory: IDataContextFactory
{
public IDataContext CreateInstance()
{
var context = IoC.Resolve<IDataContext>();
// Do any common setup or initialization that may be required on 'context'
return context;
}
}
class RepositoryFactory: IRepositoryFactory
{
public IUserRepository CreateUserRepository()
{
var repo = IoC.Resolve<IUserRepository>();
// Do any common setup or initialization that may be required on 'repo'
return repo;
}
public IAddressRepository CreateAddressRepository()
{
var repo = IoC.Resolve<IAddressRepository>();
// Do any common setup or initialization that may be required on 'repo'
return repo;
}
// etc.
}
Lợi ích của phương pháp này là, trong khi bạn không thể hoàn toàn loại bỏ sự phụ thuộc IoC chính nó, bạn có thể gói gọn nó trong một loại đối tượng đơn lẻ (một nhà máy), tách phần lớn mã của bạn khỏi thùng chứa IoC. Điều này cải thiện sự nhanh nhẹn mã của bạn trong ánh sáng, ví dụ, chuyển từ một thùng chứa IoC sang một thùng chứa IoC khác (ví dụ: Windsor thành Ninject).
Cần lưu ý, một hệ quả thú vị của việc này là các nhà máy của bạn thường được tiêm vào người phụ thuộc của họ bằng cùng một khuôn khổ IoC mà họ sử dụng. Ví dụ, nếu bạn đang sử dụng Castle Windsor, bạn sẽ tạo cấu hình để cho container IoC tiêm hai nhà máy vào thành phần kinh doanh của bạn khi nó được tạo ra. Bản thân thành phần kinh doanh cũng có thể có một nhà máy ... hoặc, nó có thể được tiêm một cách đơn giản bởi cùng một khung công tác IoC vào một thành phần mức cao hơn, v.v., quảng cáo inf.
Cảm ơn câu trả lời. Vấn đề duy nhất là IoC mà tôi đang sử dụng phải có một phạm vi, liên quan đến câu lệnh 'using'. Sau đó, nếu tôi Resolve nói 'IDataContext' nó sẽ giải quyết * cá thể duy nhất * cho phạm vi cụ thể đó. Tôi không muốn bộ điều khiển của tôi, vv để được nhận thức của một container IoC, nhưng có thực sự bất kỳ cách nào xung quanh này? – TheCloudlessSky
Điều tôi tự hỏi là nếu một Controller có thể gọi IoC.Resolve? Nếu không, ai nên thực hiện cuộc gọi này? –
TheCloudlessSky
Bạn có thể giải thích thêm một chút về phạm vi này không? Bạn đang sử dụng container IoC nào? Nói chung, việc ghép bất kỳ mã nào của bạn vào khung chứa theo bất kỳ cách nào là một loại khớp nối tiêu cực ... bạn nên tránh điều đó bằng mọi giá. Theo kinh nghiệm của tôi, một phạm vi (hoặc bối cảnh) là hiếm khi, nếu bao giờ, cần thiết cho một container IoC để làm việc. Nếu nó hoạt động theo cách đó, tôi sẽ tìm một container thay thế, hoặc tìm cách cung cấp bối cảnh đó cho các nhà máy xử lý các đối tượng của bạn và giữ cho khung IoC của bạn được tách rời càng nhiều càng tốt. – jrista