前段时间在网上看到许多跟依赖注入相关的文章,总的来说我觉得比较有道理的一句话那就是:在依赖倒置原则中,咱们在依赖的时候不应该依赖具体实现,而是要依赖抽象。本篇文章作者将以三层架构为背景从依赖注入到IOC,一步步开始讲起。
首先咱们来看依赖注入的代码:
数据访问层:
这里首先我建了一个设备接口,里面有设备读写方法
public interface IDeviceHandle
{
void Wirte();
void Read();
}
public class MitsubishiPLC : IDeviceHandle
{
public void Read()
{
Console.WriteLine("这是三菱设备的数据读取");
}
public void Wirte()
{
Console.WriteLine("这是三菱设备的数据写入");
}
}
public class OmronPLC: IDeviceHandle
{
public void Read()
{
Console.WriteLine("这是欧姆龙设备的数据读取");
}
public void Wirte()
{
Console.WriteLine("这是欧姆龙设备的数据写入");
}
}
public class SiemensPLC: IDeviceHandle
{
public void Read()
{
Console.WriteLine("这是西门子设备的数据读取");
}
public void Wirte()
{
Console.WriteLine("这是西门子设备的数据写入");
}
}
根据不同设备类来继承同一个接口,根据设备自身实现不同的读写方法。这也便于以后有新的设备则创建一个新的设备对象。
业务层:
public class Business
{
IDeviceHandle deviceHandle;
public Business(IDeviceHandle deviceHandle)
{
this.deviceHandle = deviceHandle;
}
public void Write()
{
deviceHandle.Wirte();
}
public void Read()
{
deviceHandle.Read();
}
}
业务层这里只用了抽象接口,而没有具体实现那个设备的对象的声明,真正的对象声明放在了业务类的构造函数中,这也是依赖注入中的构造注入
视图层:
static void Main(string[] args)
{
DITest();
Console.ReadKey();
}
public static void DITest()
{
Business business = new Business(new OmronPLC());
business.Write();
}
这样依赖注入的好处是,假如以后新增一个其他的设备对象,我只需要在数据访问层新增后,不会破坏其他设备内部具体实现,属于可以扩展,禁止修改,业务层也不需要修改,业务层只需要传入具体使用对象即可,降低各个层之间的耦合。但是我发现应用层在传入具体对象的时候需要实例化某个对象,这就产生了视图层对于数据访问层的依赖,而在三层架构中应该是禁止视图层对数据访问层产生依赖。使用IOC 容器(控制反转)就可以解决这个问题
IOC容器 视图层
static void Main(string[] args)
{
IOCTest();
Console.ReadKey();
}
public static void IOCTest()
{
ContainerBuilder containerBuilder = new ContainerBuilder();
var xxx = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "DAL.dll");
List<string> vs = new List<string>();
XMLHelp xMLHelp = new XMLHelp();
vs = xMLHelp.ReadNodeData();
foreach (string str in vs)
{
containerBuilder.RegisterAssemblyTypes(xxx).Where(x => x.Name == str).Named<IDeviceHandle>(str).AsImplementedInterfaces(); //注册的时候声明名字,方便实例指定
}
IContainer container = containerBuilder.Build();//获取关系存放在集合中
if (container.IsRegisteredWithName<IDeviceHandle>("OmronPLC")) //查询是否已经注册
{
IDeviceHandle deviceHandle = container.ResolveNamed<IDeviceHandle>("OmronPLC");// 假如已经注册则执行
deviceHandle.Wirte();
}
}
这里我使用的是AutoFac IOC容器,具体怎么使用这里就不详细说明了,具体还是聊聊对于架构的理解,这里IOC容器的作用就是把原本对业务层的依赖注入转到IOC容器中,而IOC会把数据访问层的对象一一注册,我在这里的话是通过外部文件实现多个注册(一个个注册太麻烦了,假如上百个对象那就要敲上百个注册),再根据视图层传入对象名字去实例化指定对象(其实可以全部根据外部文件去做需求订制),这样视图层不需要依赖到数据访问层,符合三层架构的设计规则,也就是说视图层目前只依赖IOC容器,这样耦合也大幅度降低。