相比较传统的工厂模式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 } 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就是实现类。app