美文网首页.NETAsp.net开发
设计模式之超级工厂模式【附源码】

设计模式之超级工厂模式【附源码】

作者: LuyaoCore | 来源:发表于2021-01-09 00:41 被阅读0次

    什么是工厂模式?

    在我们日常编程中,经常会使用"new"关键字来创建一个对象,此时上下游代码处于高度耦合状态,当需求变化我们就不得不同时去修改上游代码和下游源码,这显然违背了开闭原则(Open-Close Principle)。
    工厂即负责生产对象的一个类,工厂模式的出现,也正是为了解决这个问题。

    为什么叫超级工厂模式?

    相比于简单工厂而言,超级工厂扩展时对源码无任何修改。
    相比于抽象工厂而言,超级工厂代码简单且无需繁琐的配置。
    真正实现了零损耗,无责任扩展。

    实现原理

    利用反射,将所有继承了IBase接口的类放入工厂的容器中,使用时传入类的完整命名空间,即可得到所需类的实例。
    实现例子中使用的语言是C#9.0(低版本的C#也可以,只是一些语法糖需要自己替换一下)。

    实现过程

    首先我们需要一个顶层接口,所有继承该接口地类都会自动被注册到容器中。

    namespace 工厂模式
    {
      /// <summary>
      /// 基础该接口的类 回自动放入实例中
      /// </summary>
      public interface IBase
      {
      }
    }
    

    然后再来个IHuman接口去继承IBase接口

    
    namespace 工厂模式
    {
        /// <summary>
        /// 人类
        /// </summary>
        public interface IHuman:IBase
        {
        }
    }
    

    实现一下IHuman,该实现类会在初始化时自动向控制打印一句话。

    namespace 工厂模式
    {
        /// <summary>
        /// 销售人员
        /// </summary>
        public class WebMaker : IHuman
        {
            public WebMaker()
            {
                Console.WriteLine("您好,我是一个web开发人员");
            }
        }
    }
    

    接下来就可以开始写我们的超级工厂了

    namespace 工厂模式
    {
        /// <summary>
        /// 工厂客户端
        /// </summary>
        public static class SuperFactory
        {
            /// <summary>
            /// 定义一个容器来储存所有的类型
            /// string:类型命名空间
            /// Type:具体的类型
            /// </summary>
            private static Dictionary<string,Type> DicInstance;
    
            /// <summary>
            /// 初始化容器
            /// </summary>
            static SuperFactory()
            {
                IOCBuilder();//初始化类容器DicInstance
            }
    
            /// <summary>
            /// 获取实例
            /// </summary>
            /// <param name="classNamespace">命名空间</param>
            /// <returns></returns>
            public static object GetInstance(string classNamespace)
            {
                //如果字典里不存在则直接返回null
                if (!DicInstance.ContainsKey(classNamespace))
                    return null;
    
                //获取到具体的类型
                var res = DicInstance[classNamespace];
                //创建并返回类型的实例
                return res.Assembly.CreateInstance(res.FullName);
            }
    
            /// <summary>
            /// 找到所有子类
            /// </summary>
            /// <returns></returns>
            private static void IOCBuilder()
            {
                DicInstance ??= new Dictionary<string, Type>();
    
                //获取顶层接口类型
                var parentType = typeof(IBase);
                //反射获取parentType所在程序集的所有类
                var assemTypes = Assembly.GetAssembly(parentType).GetTypes();
                foreach (Type tChild in assemTypes)
                {
                    //如果当前类没有继承IBase接口 则跳过
                    if (!tChild.GetInterfaces().Contains(parentType))
                        continue;
                    //如果当前类已经被注入到容器中 则跳过
                    if (DicInstance.ContainsKey(tChild.FullName))
                        continue;
    
                    //注入容器
                    DicInstance.Add(tChild.FullName, tChild);
                }
            }
        }
    }
    
    

    开始调用:

    SuperFactory.GetInstance("工厂模式.WebMaker");
    

    输出结果:


    输出结果

    如果我们现在需要扩展出一个Apple类的话,只需要两步,且完全不需要修改任何东西:

    1:抽象一个IFruit类继承IBase类:

    namespace 工厂模式
    {
        public interface IFruit:IBase
        {
        }
    }
    
    

    2.实现Apple类:

    namespace 工厂模式
    {
        public class Apple: IFruit
        {
            public Apple()
            {
                Console.WriteLine("我是一个苹果");
            }
        }
    }
    

    然后再客户端就可以直接调用了:


    输出结果

    源码地址(Github):https://github.com/Luyao1996/DesignPatterns

    如果有什么不对或者还可以优化的地方,欢迎私信或者在下方留言指正,不盛感激。
    最后,若本文为您带来了帮助,还请不要吝惜您的""

    相关文章

      网友评论

        本文标题:设计模式之超级工厂模式【附源码】

        本文链接:https://www.haomeiwen.com/subject/tkjciktx.html