简单工厂模式
创建一个工厂类,对实现了同一个接口的多个类进行实例的创建。
//抽象类 人
public abstract class HuMan
{
public abstract void Talk();
}
//黑人实现类
public class BlackHuman : HuMan
{
public override void Talk()
{
Console.WriteLine("I am BlackHuman");
}
}
//白人实现类
public class WhiteHuman : HuMan
{
public override void Talk()
{
Console.WriteLine("I am WhiteHuman");
}
}
/// <summary>
/// 简单工厂
/// </summary>
public static class HumanFactory
{
public static HuMan CreateHuman(HumanEnum humanEnum)
{
HuMan huMan = null;
switch (humanEnum)
{
case HumanEnum.Black:
huMan = new BlackHuman();
break;
case HumanEnum.White:
huMan = new WhiteHuman();
break;
default:
throw new NullReferenceException();
}
return huMan;
}
}
//客户端调用
//创建一个白人
var whiteHuman1 = SimpleFactory.CreateHuman(HumanEnum.White);
whiteHuman1.Talk();
//创建一个黑人
var blackHuman1 = SimpleFactory.CreateHuman(HumanEnum.Black);
blackHuman1.Talk();
![]()
优点:工厂中包含了必要的逻辑判断,根据客户端的选择条件动态的创建相关的类,对于客户端来说,它只需要提供创建实现类的参数,隐藏了创建实例的细节,去除了对具体实现类的依赖。
缺点:当要新增一个实现类时,需要修改工厂类的代码(switch下增加一个Case),违背了开放-封闭原则。
当然上面的代码其实还存在很大的优化空间,我们可以先看下工厂模式的实现方案,对比下两种模式上的区别。
工厂模式
定义一个用于创建对象的接口,让子类决定实现哪个类。工厂方法将创建对象实例的职责移交给了子类。
//定义一个创建人类的工厂接口
public interface IHumanFactory
{
HuMan CreateHuman();
}
//定义一个创建白人的工厂
public class WhiteHumanFactory : IHumanFactory
{
public HuMan CreateHuman()
{
return new WhiteHuman();
}
}
//定义一个创建黑人的工厂
public class BlackHumanFactory : IHumanFactory
{
public HuMan CreateHuman()
{
return new BlackHuman();
}
}
//客户端调用
var whiteHumanFactory = new WhiteHumanFactory();
var whiteHuman2 = whiteHumanFactory .CreateHuman();
whiteHuman2.Talk();
var blackHumanFactory = new BlackHumanFactory();
var blackHuman2 = blackHumanFactory .CreateHuman();
blackHuman2.Talk();
优点:当要新增一个实现类时,只需要再增加一个实现类和创建实现类的工厂,不需要修改原有工厂的代码,保留了简单工厂对创建实例的封装,又体现了开放-封闭原则。
缺点:客户端需要决定实例化哪一个工厂来创建实现类,增加了客户端的复杂度。同时每增加一个实现类,也要增加一个工厂类,增加了代码复杂度。
简单工厂+反射
可以通过反射技术来强化简单工厂,让简单工厂同样符合开放封闭原则。
/// <summary>
/// 简单工厂
/// </summary>
public static class HumanFactory
{
public static HuMan CreateHuman(string humanType)
{
var a = Assembly.LoadFrom($"{AppDomain.CurrentDomain.BaseDirectory}DesignPatterns.Model.dll");
return (HuMan)a.CreateInstance($"DesignPatterns.Model.Factory.{humanType}");
}
}
客户端可以通过配置文件或者数据库中获取humanType(在程序或者数据库中维护一个参数类型+类名的字典),通过反射技术动态的创建实例。
简单工厂+依赖注入
//工厂类
public class HumanFactory
{
private readonly Func<HumanEnum, Human> _func;
public HumanFactory(Func<HumanEnum, Human> func)
{
this._func = func;
}
public Human CreateHuman(HumanEnum humanEnum)
{
return _func(humanEnum);
}
}
public static class HunmanDependencyInjection
{
//维护一个实现类的字典
private static Dictionary<HumanEnum, Type> dicHuman = new Dictionary<QRCodeType, Type>() {
{ HumanEnum.White,typeof(WhiteHuman)},
{ HumanEnum.Black,typeof(BlackHuman)}
};
public static void AddHuman(this IServiceCollection serviceCollection)
{
serviceCollection.AddScoped<WhiteHuman>();
serviceCollection.AddScoped<BlackHuman>();
serviceCollection.AddScoped(factory=> {
Func<HumanEnum, Human> func = humanType=> {
return (Human)factory.GetService(dicHuman [humanType]);
};
return func;
});
serviceCollection.AddScoped<HumanFactory>();
}
}
//在Startup中注入实现类和工厂
public void ConfigureServices(IServiceCollection services)
{
services.AddHuman();
services.AddMvc();
}
//客户端在构造函数中引入HumanFactory
var whiteHuman = HumanFactory.CreateHuman(HumanEnum.White);
whiteHuman.Talk();
![]()
这样我们就用Ioc实现了一个简单工厂,上面的代码示例是将实现类的字典放在工厂中维护,其实可以将字典放到配置文件或者数据库中维护,这样我们再增加新的实现类时,就不需要在修改工厂的代码,实现了实现类的动态扩展。也体现了开闭原则。


















