使用 IoC 容器构建可插拔应用程序
在本文中,我将展示如何使用 IoC 容器构建一个可插拔应用程序。
引言
在构建应用程序时,我们总是面临应用程序开发期间和之后的许多更改。提前为变更做好准备是灵活应用程序的关键特征。 IoC 容器代表控制反转容器。它经常用于我们不想在应用程序中直接硬编码合同/接口实现的逻辑的情况。通过遵循合同优先的设计原则并将实例化责任传递给 IoC 容器,我们可以创建一个可扩展且灵活的应用程序。
演示应用程序
假设我们要设计一个可以将文本输出到不同输出通道(例如文件输出通道和控制台输出通道)的应用程序。我们首先可以做的是定义一个输出合同,以便主应用程序遵循该合同输出文本,而无需知道具体的输出通道。
public interface IOutputService
{
void WriteLine(string data);
}
定义合同后,我们可以有两种不同的实现,即文件输出通道和控制台输出通道。
文件输出
:
public class FileOutput: IOutputService
{
public void WriteLine(string data)
{
using (StreamWriter sw = new StreamWriter("test.txt", false))
{
sw.WriteLine(data);
}
}
}
控制台输出
:
public class ConsoleOutput: IOutputService
{
public void WriteLine(string data)
{
Console.Write(data);
}
}
在应用程序中获取输出通道的最简单方法是拥有一个通道工厂,该工厂将创建所请求的输出通道的实例。 但是,这样做会将实例化逻辑硬编码到我们的应用程序中。 如果我们想添加一个新的输出通道,例如网络输出通道,那么我们唯一的意见就是更改代码。
使演示应用程序可插拔
借助 IoC 容器,我们可以轻松地创建一个可插拔应用程序,而无需进行太多编码。 想法是定义一个基本库,它将具有如下的 API
public interface IIoCContainer
{
T Resolve<t>();
IEnumerable<t> ResolveAll<t>();
}
此 API 为应用程序提供了一种检索指定类型的单个实例或实例集合的方法,因此您可以使用 IOutputService
interface
来获取特定的输出通道。 IoC 容器 API 允许我们使用任何 IoC 容器,例如 Unity
或 StructureMap。 在应用程序启动时,我们使用 BootStrapper
来设置 IoC 容器。
BootStrapper
:
public class BootStrapper
{
public static void StartUp()
{
RegisterIoCContainer();
}
private static void RegisterIoCContainer()
{
ObjectFactory.Initialize(x => { x.PullConfigurationFromAppConfig = true; });
IoC.IoCContainerManager.IoCContainer = new StructureMapIoCContainer();
}
}
使用 BootStrapper
初始化 IoC 容器。
BootStrapper.StartUp();
初始化 IoC 容器后,应用程序可以直接使用 IoC 容器 API 来获取 IOutputService
。
IEnumerable<ioutputservice> outputServices =
IoC.IoCContainerManager.IoCContainer.ResolveAll<ioutputservice>();
outputServices.ToList().ForEach(o => o.WriteLine("Hello World!"));
为了使我们的应用程序更加灵活,并允许我们在生产环境中切换不同的输出通道而无需重新编译,我决定不直接在主应用程序中引用输出通道实现。
输出通道实现将通过后期生成事件命令行复制到主应用程序中。
IOutputService
和实际实现之间的映射在应用程序配置文件中定义。
<configSections>
<section name="StructureMap"
type="StructureMap.Configuration.StructureMapConfigurationSection,StructureMap"/>
</configSections>
<StructureMap>
<PluginFamily Type="OutputService.IOutputService"
Assembly="OutputService" DefaultKey="Default">
<Plugin Type="FileOutput.FileOutput"
Assembly="FileOutput" ConcreteKey="Default"/>
<Plugin Type="ConsoleOutput.ConsoleOutput"
Assembly="ConsoleOutput" ConcreteKey="Console"/>
</PluginFamily>
</StructureMap>
整个应用程序如何工作
当调用 IoCContainer.ResolveAll<ioutputservice>()
时,应用程序会将调用转发到 IoC 容器,然后 IoCContainer
将基于配置文件中的映射来获取特定的实现。
在获取 IOutputService
的集合后,调用 IOutputService
的 WriteLine
将“Hello World
”写入到每个输出通道。
摘要
借助 IoC 容器,我们可以快速实现一个简单的可插拔应用程序。 这个可插拔应用程序可以利用配置文件为定义的合同添加新的实现,而无需更改代码。
Using the Code
该代码在 Visual Studio 2010 中开发。您可以创建自己的 IOutputService
实现并将其添加到配置文件中,以尝试该演示应用程序。