设计模式(五) 简单工厂模式+工厂模式

简单工厂模式

   创建一个工厂类,对实现了同一个接口的多个类进行实例的创建。

//抽象类 人
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();
View Code

   优点:工厂中包含了必要的逻辑判断,根据客户端的选择条件动态的创建相关的类,对于客户端来说,它只需要提供创建实现类的参数,隐藏了创建实例的细节,去除了对具体实现类的依赖。

   缺点:当要新增一个实现类时,需要修改工厂类的代码(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();
View Code

优点:当要新增一个实现类时,只需要再增加一个实现类和创建实现类的工厂,不需要修改原有工厂的代码,保留了简单工厂对创建实例的封装,又体现了开放-封闭原则。

缺点:客户端需要决定实例化哪一个工厂来创建实现类,增加了客户端的复杂度。同时每增加一个实现类,也要增加一个工厂类,增加了代码复杂度。

简单工厂+反射

  可以通过反射技术来强化简单工厂,让简单工厂同样符合开放封闭原则。

/// <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}");
    }
}
View Code

客户端可以通过配置文件或者数据库中获取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();
View Code

这样我们就用Ioc实现了一个简单工厂,上面的代码示例是将实现类的字典放在工厂中维护,其实可以将字典放到配置文件或者数据库中维护,这样我们再增加新的实现类时,就不需要在修改工厂的代码,实现了实现类的动态扩展。也体现了开闭原则。

原文地址:https://www.cnblogs.com/jasonbourne3/p/14099858.html