• 模式:工程化实现及扩展——工厂模式


    相比较传统的工厂模式IFactory/Concrete Factory会反复引用并编译代码
    但是作为开发人员,我们更希望的是少修改代码,尽量从配置着手也就是设计模式的根本原则之一:开放封闭原则。如果我要增加新的产品,那么修改就比较大了,对于业务来讲还是可以接受的。但是如果可以做到不修改代码是最好的。上一份工作中,我印象最深的一句话就是我上司对我说的"能不改代码就别改,能写进配置里的就写到配置里"。因此我们将要增加的工厂类写到配置里面。如此,新的产品类型和工厂类型即便在系统上线后仍可以通过修改配置文件的方式不断补充。但是,还有一个问题,我们仍然需要为每"类"抽象产品定制特定的工厂接口并实现之,也就是"多头管理"问题。泛型可以用来解决这个问题,我们定义一个泛型工厂即可。代码如下:

    /// <summary>
    /// 工厂接口定义
    /// </summary>
    /// <remarks>
    /// TTarget: 抽象产品类型
    /// TSource: 具体产品类型
    /// </remarks>
    public interface IFactory
    {
        #region config and register type mapping
    
        /// <summary>
        /// 如果需要同时加载配置文件中定义的映射关系,可以按照SRP的原则定义独立的配置类型。
        /// 由该配置类型调用这两个接口为Factory加载配置信息
        /// </summary>
    
        IFactory RegisterType<TTarget, TSource>();  // 注入产品
        IFactory RegisterType<TTarget, TSource>(string name);   // 注入产品
    
        #endregion
    
        #region factory method
    
        TTarget Create<TTarget>();
        TTarget Create<TTarget>(string name);
    
        #endregion
    }
    
    /// <summary>
    /// 充当 依赖注入 的角色
    /// </summary>
    public sealed class TypeRegistry
    {
        /// <summary>
        /// default name in type mappings
        /// </summary>
        readonly string DefaultName = Guid.NewGuid().ToString();
    
        /// <summary>
        /// Type        :   TTarget, 抽象产品类型
        /// IDictionary<string ,Type>
        ///     string  :   name
        ///     Type    :   TSource, 具体产品类型
        /// </summary>
        IDictionary<Type, IDictionary<string, Type>> registry =
            new Dictionary<Type, IDictionary<string, Type>>();
    
        public void RegisterType(Type targetType, Type sourceType)
        {
            RegisterType(targetType, sourceType, DefaultName);
        }
    
        public void RegisterType(Type targetType, Type sourceType, string name)
        {
            if(targetType == null) throw new ArgumentNullException("targetType");
            if(sourceType == null) throw new ArgumentNullException("sourceType");
            if(string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
    
            if (!registry.TryGetValue(targetType, out IDictionary<string, Type> subDictionary))
            {
                subDictionary = new Dictionary<string, Type>
                {
                    { name, sourceType }
                };
                registry.Add(targetType, subDictionary);
            }
            else
            {
                if (subDictionary.ContainsKey(name))
                    throw new Exception($"{name}重复");
                subDictionary.Add(name, sourceType);
            }
        }
    
        public Type this[Type targetType, string name]
        {
            get
            {
                if (targetType == null) throw new ArgumentNullException("targetType");
                if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
                if (registry.Count() == 0)
                    return null;
    
                return 
                    (registry.Where(x => x.Key == targetType)).FirstOrDefault().Value
                        .Where(x => string.Equals(name, x.Key)).FirstOrDefault().Value;
            }
        }
    
        public Type this[Type targetType]
        {
            get { return this[targetType, DefaultName]; }
        }
    }
    
    public class Factory : IFactory
    {
        protected TypeRegistry registry = new TypeRegistry();
    
        #region IFactory Members
    
        public IFactory RegisterType<TTarget, TSource>()
        {
            registry.RegisterType(typeof(TTarget), typeof(TSource));
            return this;
        }
    
        public IFactory RegisterType<TTarget, TSource>(string name)
        {
            registry.RegisterType(typeof(TTarget), typeof(TSource), name);
            return this;
        }
    
        public TTarget Create<TTarget>()
        {
            return (TTarget)Activator.CreateInstance(registry[typeof(TTarget)]);
        }
    
        public TTarget Create<TTarget>(string name)
        {
            return (TTarget)Activator.CreateInstance(registry[typeof(TTarget), name]);
        }
    
        #endregion
    }
    

    上面的示例表明新的工厂类型不仅可以完成经典工厂方法模式所希望实现的各项要求,也满足抽象工厂的要求,同时他可以作为整个项目一个独立的而且是唯一的工厂入口,供项目中各子系统访问和使用。原因在于它的底层将工厂接口与抽象产品类型的依赖关系变成基于CLR"万能工厂"类型Activator基于参数Type的构造。
    工厂管理的是其内的产品。我们的工厂接口IFactory有两个功能,一个是往工厂中注入产品,一个是创建指定产品的实例。借助RegisterType将配置文件中定义的类型映射方希加载到新的具体工厂类型中,也就是重载函数中的参数(name)。我们通过字典Dictionary来管理维护工厂内的产品,将抽象产品也就是接口或是抽象类作为key,要考虑到同一接口可以有多个不同的实现,因此我们再维护一个实现类的字典,使用一个唯一的标识作为key就行,value就是实现类。

  • 相关阅读:
    GitHub 集成在Windows Azure Web Site中
    WebMatrix 2发布了!添加了新的Windows Azure 功能
    客户文章: 10gen和微软合作伙伴在云端提供NoSql数据库
    VC++实现IP与ARP信息获取,可以同理实现APR攻击
    现实世界中的 Windows Azure: 刚刚起步的LiquidSpace借助Windows Azure快速发展
    VC++实现遍历所有进程的TCP与UDP链接
    Node.js 体验存储服务和服务运行时
    客户文章:Windows Azure SendGrid入门
    2005年大学毕业生的求职新战略
    WinAPI: RoundRect 绘制圆角矩形
  • 原文地址:https://www.cnblogs.com/zhiyong-ITNote/p/11173525.html
Copyright © 2020-2023  润新知