经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
模式:工程化实现及扩展——工厂模式
来源:cnblogs  作者:又见阿郎  时间:2019/7/12 9:22:16  对本文有异议

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

  1. /// <summary>
  2. /// 工厂接口定义
  3. /// </summary>
  4. /// <remarks>
  5. /// TTarget: 抽象产品类型
  6. /// TSource: 具体产品类型
  7. /// </remarks>
  8. public interface IFactory
  9. {
  10. #region config and register type mapping
  11. /// <summary>
  12. /// 如果需要同时加载配置文件中定义的映射关系,可以按照SRP的原则定义独立的配置类型。
  13. /// 由该配置类型调用这两个接口为Factory加载配置信息
  14. /// </summary>
  15. IFactory RegisterType<TTarget, TSource>(); // 注入产品
  16. IFactory RegisterType<TTarget, TSource>(string name); // 注入产品
  17. #endregion
  18. #region factory method
  19. TTarget Create<TTarget>();
  20. TTarget Create<TTarget>(string name);
  21. #endregion
  22. }
  23. public sealed class TypeRegistry
  24. {
  25. /// <summary>
  26. /// default name in type mappings
  27. /// </summary>
  28. readonly string DefaultName = Guid.NewGuid().ToString();
  29. /// <summary>
  30. /// Type : TTarget, 抽象产品类型
  31. /// IDictionary<string ,Type>
  32. /// string : name
  33. /// Type : TSource, 具体产品类型
  34. /// </summary>
  35. IDictionary<Type, IDictionary<string, Type>> registry =
  36. new Dictionary<Type, IDictionary<string, Type>>();
  37. public void RegisterType(Type targetType, Type sourceType)
  38. {
  39. RegisterType(targetType, sourceType, DefaultName);
  40. }
  41. public void RegisterType(Type targetType, Type sourceType, string name)
  42. {
  43. if(targetType == null) throw new ArgumentNullException("targetType");
  44. if(sourceType == null) throw new ArgumentNullException("sourceType");
  45. if(string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
  46. if (!registry.TryGetValue(targetType, out IDictionary<string, Type> subDictionary))
  47. {
  48. subDictionary = new Dictionary<string, Type>
  49. {
  50. { name, sourceType }
  51. };
  52. registry.Add(targetType, subDictionary);
  53. }
  54. else
  55. {
  56. if (subDictionary.ContainsKey(name))
  57. throw new Exception($"{name}重复");
  58. subDictionary.Add(name, sourceType);
  59. }
  60. }
  61. public Type this[Type targetType, string name]
  62. {
  63. get
  64. {
  65. if (targetType == null) throw new ArgumentNullException("targetType");
  66. if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
  67. if (registry.Count() == 0)
  68. return null;
  69. return
  70. (registry.Where(x => x.Key == targetType)).FirstOrDefault().Value
  71. .Where(x => string.Equals(name, x.Key)).FirstOrDefault().Value;
  72. }
  73. }
  74. public Type this[Type targetType]
  75. {
  76. get { return this[targetType, DefaultName]; }
  77. }
  78. }
  79. public class Factory : IFactory
  80. {
  81. protected TypeRegistry registry = new TypeRegistry();
  82. #region IFactory Members
  83. public IFactory RegisterType<TTarget, TSource>()
  84. {
  85. registry.RegisterType(typeof(TTarget), typeof(TSource));
  86. return this;
  87. }
  88. public IFactory RegisterType<TTarget, TSource>(string name)
  89. {
  90. registry.RegisterType(typeof(TTarget), typeof(TSource), name);
  91. return this;
  92. }
  93. public TTarget Create<TTarget>()
  94. {
  95. return (TTarget)Activator.CreateInstance(registry[typeof(TTarget)]);
  96. }
  97. public TTarget Create<TTarget>(string name)
  98. {
  99. return (TTarget)Activator.CreateInstance(registry[typeof(TTarget), name]);
  100. }
  101. #endregion
  102. }

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

原文链接:http://www.cnblogs.com/zhiyong-ITNote/p/11173525.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号