我们已经很习惯于使用工厂模式来创建对象,作为最常用的设计模式,可以让客户端非常容易地在多个产品类型中切换。尽管客户端使用接口或者抽象类来调用产品方法,但是我们依然无法摆脱具体的产品类,我们必须引用最终产品类库来创建目标产品对象,这是工厂模式的弊端。如果使用模板方法,我们就必须将产品接口和抽象类作为单独的类库打包,否则模板方法所在类库和最终产品类库间就会形成循环引用(见
系统架构设计 & 避免循环引用…… )。如此一来,客户端还是需要依赖于两个类库。
IOC模式的具体含义,网上已经说得很多了,我在此不做详述。利用 .net 强大的反射机制,我们可以轻松实现IOC机制,即保留了工厂模式的便利,又拥有了随意更换产品类型而无需修改代码的好处。
ConsoleApplication1.csproj
Learn.Library.csproj
在上面代码的例子中,客户端(Program.Main)不再依赖于具体的产品类,通过产品类型字符串动态创建产品实例,无论该产品是现有的(ClassASon1),还后后来重新添加的(ClassASon2);也不再引用目标产品类库(Learn.Library)。将客户端(Main)中创建子类的参数字符串保存到配置文件,我们就可以任意添加新的产品,任意切换产品类型,而无需更改任何客户端代码了。
其实在 .net Framework 2.0 中,有大量使用IOC的例子。
如:
System.Data.Common.DbProviderFactories
System.Security.Cryptography.AsymmetricAlgorithm
System.Web.Security.MembershipProvider
System.Web.Security.RoleProvider
System.Web.Profile.ProfileProvider
等等……
当然,本文介绍的IOC过于简陋。有关高级实现可以参考 Sprint.NET。
IOC模式的具体含义,网上已经说得很多了,我在此不做详述。利用 .net 强大的反射机制,我们可以轻松实现IOC机制,即保留了工厂模式的便利,又拥有了随意更换产品类型而无需修改代码的好处。
ConsoleApplication1.csproj
using System;
using System.Collections;
using System.Collections.Generic;
namespace ConsoleApplication1
{
public abstract class ClassA
{
public abstract void Test();
public static ClassA Create(string name)
{
return Activator.CreateInstance(Type.GetType(name)) as ClassA;
}
public static ClassA Create(string assembly, string name)
{
Assembly asm = Assembly.LoadFile(assembly);
return asm.CreateInstance(name) as ClassA;
}
}
public class ClassASon1 : ClassA
{
public override void Test()
{
Console.WriteLine("ClassASon1 Test...");
}
}
class Program
{
static void Main()
{
ClassA.Create("ConsoleApplication1.ClassASon1").Test();
ClassA.Create(@"Learn.Library.dll", "Learn.Library.ClassASon2").Test();
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
}
}
using System.Collections;
using System.Collections.Generic;
namespace ConsoleApplication1
{
public abstract class ClassA
{
public abstract void Test();
public static ClassA Create(string name)
{
return Activator.CreateInstance(Type.GetType(name)) as ClassA;
}
public static ClassA Create(string assembly, string name)
{
Assembly asm = Assembly.LoadFile(assembly);
return asm.CreateInstance(name) as ClassA;
}
}
public class ClassASon1 : ClassA
{
public override void Test()
{
Console.WriteLine("ClassASon1 Test...");
}
}
class Program
{
static void Main()
{
ClassA.Create("ConsoleApplication1.ClassASon1").Test();
ClassA.Create(@"Learn.Library.dll", "Learn.Library.ClassASon2").Test();
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
}
}
Learn.Library.csproj
using System;
using System.Collections.Generic;
using System.Text;
namespace Learn.Library
{
public class ClassASon2 : ConsoleApplication1.ClassA
{
public override void Test()
{
Console.WriteLine("ClassASon2 Test...");
}
}
}
using System.Collections.Generic;
using System.Text;
namespace Learn.Library
{
public class ClassASon2 : ConsoleApplication1.ClassA
{
public override void Test()
{
Console.WriteLine("ClassASon2 Test...");
}
}
}
在上面代码的例子中,客户端(Program.Main)不再依赖于具体的产品类,通过产品类型字符串动态创建产品实例,无论该产品是现有的(ClassASon1),还后后来重新添加的(ClassASon2);也不再引用目标产品类库(Learn.Library)。将客户端(Main)中创建子类的参数字符串保存到配置文件,我们就可以任意添加新的产品,任意切换产品类型,而无需更改任何客户端代码了。
其实在 .net Framework 2.0 中,有大量使用IOC的例子。
如:
System.Data.Common.DbProviderFactories
System.Security.Cryptography.AsymmetricAlgorithm
System.Web.Security.MembershipProvider
System.Web.Security.RoleProvider
System.Web.Profile.ProfileProvider
等等……
当然,本文介绍的IOC过于简陋。有关高级实现可以参考 Sprint.NET。