最近,接触到了一些.NET平台上的IOC(控制反转)工具,并对依赖注入的概念产生了浓厚的兴趣。尽管这些工具在实际应用中非常有效,但随着时间的推移,它们的复杂性也在增加,这让有些望而却步。为了简化这个过程,决定自己动手实现一个简易的IOC容器。
根据维基百科的定义,依赖注入是一种设计模式,其核心原则是将行为与依赖解析分离。换句话说,它是一种解耦高度依赖的软件组件的技术。
传统上,开发者习惯于硬编码依赖项,这使得代码紧密耦合,并且随着需求的变化,需要不断地修改代码。这显然违反了DRY(Don't Repeat Yourself)原则,因为开发者可能需要修改整个代码流程或复制方法来支持变化。依赖注入通过实现接口来提供所需的功能,从而帮助解决这个问题。DI框架可以在运行时注入从这个接口继承的对象,从而在可能的情况下提前加载对象。
这是一个轻量级的依赖注入容器,目前还在开发阶段,但已经能够满足大多数常见的需求。这个框架已经通过了最初设想的一些测试用例。虽然它目前还缺少Ninject和Unity等框架的一些特性,但会随着时间的推移不断更新它。目前,它已经能够帮助减少样板代码。
当前的实现展示了这个DI框架的工作方式。当用户注入类型或对象时,它会在内部的Object容器中维护这些对象,这个容器只能被框架内部访问。目前,这个框架支持有无上下文的池。上下文在这里意味着在该键下注册的类型/对象的目录。这有助于用户在不同的上下文中注册相同的类型,并使用相同的名称。
这个类(静态)维护对象池和上下文池:
方法:
注册和解析对象:
方法:
告诉容器每次调用时创建新对象
EventArgument返回调用BeginResolve时的对象:
public interface IDriveLayout {
string Name { get; }
}
public interface IEngineLayout {
string Name { get; }
}
class RearMidEngine : IEngineLayout {
public string Name {
get {
return "Rear Mid Engine";
}
}
}
class RearWheelDrive : IDriveLayout {
public string Name {
get {
return "Rear Wheel Drive";
}
}
}
public class Vehicle {
private IDriveLayout _driveLayout;
private IEngineLayout _engineLayout;
public string DriveType {
get {
return _driveLayout.Name;
}
}
public string EngineType {
get {
return _engineLayout.Name;
}
}
public virtual string Name {
get {
return "Vehicle";
}
}
public Vehicle(IDriveLayout driveLayout, IEngineLayout engineLayout) {
_driveLayout = driveLayout;
_engineLayout = engineLayout;
}
}
class FerrariF430 : Vehicle {
public FerrariF430(IDriveLayout driveLayout, IEngineLayout engineLayout)
: base(driveLayout, engineLayout) { }
public override string Name {
get {
return "Ferrari F430";
}
}
}
ObjectPoolManager.Pool.Register("RearWheelDrive");
ObjectPoolManager.Pool.Register("RearMidEngine");
ObjectPoolManager.Pool.Register("FerrariF430", () =>
new FerrariF430(
ObjectPoolManager.Pool.Resolve("RearWheelDrive"),
ObjectPoolManager.Pool.Resolve("RearMidEngine")
)
);
var vehicle = ObjectPoolManager.Pool.Resolve("FerrariF430");
Console.WriteLine("{0} -> Layout: {1}, {2}", vehicle.Name, vehicle.EngineType, vehicle.DriveType);
Console.ReadLine();