目录

观众

问题

解决方案

讨论


Download source code - 1.7 MB

(译者注:Demo中CleanFactory为新解决方案,DirtyFactory为问题中提到的解决方案)

观众

本文希望观众熟悉依赖倒置原则(DIP)和工厂设计模式。为简单起见,代码不具有防御性,并且没有受到保护的声明。代码使用简单注射器(Simple Injector),但所描述的原则也适用于其他IoC容器框架。

问题

在使用控制反转(IoC)容器的项目中实现工厂类时,如果您得到下面描述的解决方案,那么本文是为你准备的:

using System;
using DirtyFactory.Dependencies;namespace DirtyFactory.Processors
{internal class ProcessorFactory : IProcessorFactory{private readonly IDependencyOne _depOne;private readonly IDependencyTwo _depTwo;private readonly IDependencyThree _depThree;public ProcessorFactory(IDependencyOne depOne, IDependencyTwo depTwo, IDependencyThree depThree){depOne = depOne;depTwo = depTwo;depThree = depThree;}public IProcessor Create(RequestType requestType){switch(requestType){case RequestType.Internal:return new InternalProcessor(_depOne, _depTwo);case RequestType.External:return new ExternalProcessor(_depOne, _depThree);default:throw new NotImplementedException();}}}
}

示例代码是处理器工厂类实现,它包含一个名为Create的工厂方法和一个构造函数。

上述解决方案的主要问题是工厂类通过其构造函数注入其处理器的依赖项。InternalProcessor依赖于IDependencyOne和IDependencyTwo, 而ExternalProcessor则依赖于IDependencyOne和IDependencyThree。结果是工厂类依赖于IDependencyOne,IDependencyTwo和IDependencyThree。另一个结果是,如果稍后添加新处理器,则还需要在工厂类构造函数中容纳新处理器的依赖项。

下面是使用Simple Injector 4.0.12容器的主程序。该代码通过构造函数注入应用依赖倒置原则,并利用容器配置类组合。

using System;
using DirtyFactory.Dependencies;
using DirtyFactory.Processors;
using SimpleInjector;namespace DirtyFactory
{internal class Program{internal  static IProcessorFactory _processorFactory;static void Main(string[] args){//1.register the containerContainer container = GetRegisteredContainer();//2.simulate the internal state of the program_processorFactory = container.GetInstance<IProcessorFactory>();//3.each of this request below simulate independant executing of the programRunRequest(RequestType.Internal);RunRequest(RequestType.External);Console.ReadKey();}private static void RunRequest(RequestType requestType){IProcessor internalProcessor = _processorFactory.Create(requestType);Console.WriteLine(internalProcessor.GetResponse());                       }private static Container GetRegisteredContainer(){SimpleInjector.Container container = new SimpleInjector.Container();container.Register<IDependencyOne, DependencyOne>();container.Register<IDependencyTwo, DependencyTwo>();container.Register<IDependencyThree, DependencyThree>();container.Register<IProcessorFactory, ProcessorFactory>();return container;}}
}

以下是代码的其余部分:

using DirtyFactory.Dependencies;namespace DirtyFactory.Processors
{internal enum RequestType{Internal,External}internal interface IProcessorFactory{IProcessor Create(RequestType requestType);}internal interface IProcessor{string GetResponse();}internal class ExternalProcessor : IProcessor{private readonly IDependencyOne _depOne;private readonly IDependencyThree _depThree;public ExternalProcessor(IDependencyOne depOne, IDependencyThree depThree){_depOne = depOne;_depThree = depThree;}public string GetResponse(){return "External Response";}public bool IsUser(RequestType requestType){return requestType == RequestType.External;}}internal class InternalProcessor : IProcessor{private readonly IDependencyOne _depOne;private readonly IDependencyTwo _depTwo;public InternalProcessor(IDependencyOne depOne, IDependencyTwo depTwo){_depOne = depOne;_depTwo = depTwo;}public string GetResponse(){return "Internal Response";}public bool IsUser(RequestType requestType){return requestType == RequestType.Internal;}}
}
namespace DirtyFactory.Dependencies
{internal interface IDependencyOne{}internal class DependencyOne : IDependencyOne{}internal interface IDependencyTwo{}internal class DependencyTwo : IDependencyTwo{}internal interface IDependencyThree{}internal class DependencyThree : IDependencyThree{}
}

为了简化说明,首先描述解决方案,然后稍后讨论以探索替代解决方案。

解决方案

上述问题的解决方案是推动处理器作为工厂类依赖代替。

但是,有许多变化可以使这项工作首尾相顾。

  1. 工厂类需要注入一个IProcessor集合。
  2. 先前在factory类中的切换逻辑变为集合查找。因此,每个处理器都需要有关于requestType它所服务的信息。
  3. 容器需要寄存项目中的所有IProcessor。

因此,如果添加新处理器,则工厂类和其余代码根本不需要更改,这是理想的。

以下是工厂类的更改:

using System.Collections.Generic;
using System.Linq;namespace CleanFactory.Processors
{internal class ProcessorFactory : IProcessorFactory{private readonly IEnumerable<IProcessor> _processors;public ProcessorFactory(IEnumerable<IProcessor> processors){_processors = processors;}public IProcessor Create(RequestType requestType){return _processors.Single(item => item.IsValidUser(requestType));}}
}

首先, IProcessor的集合以IEnumerable的形式通过其构造函数注入。实际上,可以使用的集合接口取决于IoC容器中支持的内容。对于简单的注入器,你可以通过IList,Array,ICollection,IReadOnlyCollection,或IEnumerable。

其次,switch语句转换为Create方法内的集合查找。为了支持这一点,一个额外的方法,名为IsValidUser被添加到IProcessor中,并且IProcessor的实现也被改变为其结果。

namespace CleanFactory.Processors
{internal interface IProcessor{bool IsValidUser(RequestType requestType);string GetResponse();}internal class InternalProcessor : IProcessor{private readonly IDependencyOne _depOne;private readonly IDependencyTwo _depTwo;public InternalProcessor(IDependencyOne depOne, IDependencyTwo depTwo){_depOne = depOne;_depTwo = depTwo;}public string GetResponse(){return "Internal Response";}public bool IsValidUser(RequestType requestType){return requestType == RequestType.Internal;}}internal class ExternalProcessor : IProcessor{private readonly IDependencyOne _depOne;private readonly IDependencyThree _depThree;public ExternalProcessor(IDependencyOne depOne, IDependencyThree depThree){_depOne = depOne;_depThree = depThree;}public string GetResponse(){return "External Response";}public bool IsValidUser(RequestType requestType){return requestType == RequestType.External;}}
}

最后,容器需要注册项目中的所有处理器。

using System;
using System.Reflection;
using CleanFactory.Dependencies;
using CleanFactory.Processors;
using SimpleInjector;namespace CleanFactory
{internal class Program{internal static IProcessorFactory _processorFactory;static void Main(string[] args){//register the containerContainer container = GetRegisteredContainer();//simulate the internal state of the program_processorFactory = container.GetInstance<IProcessorFactory>();//each of this request below simulate independant executing of the programRunRequest(RequestType.Internal);RunRequest(RequestType.External);//just to hold the programConsole.ReadKey();}private static void RunRequest(RequestType requestType){IProcessor internalProcessor = _processorFactory.Create(requestType);Console.WriteLine(internalProcessor.GetResponse());}private static Container GetRegisteredContainer(){SimpleInjector.Container container = new SimpleInjector.Container();container.Register<IDependencyOne, DependencyOne>();container.Register<IDependencyTwo, DependencyTwo>();container.Register<IDependencyThree, DependencyThree>();container.Register<IProcessorFactory, ProcessorFactory>();container.RegisterCollection<IProcessor>(new Assembly[] { Assembly.GetExecutingAssembly() });return container;}}
}

简单注入器(Simple Injector提供了多种方法进行集合注册,例如,指定数组或具体实现的IEnumerable或程序集。如果指定了程序集,则容器执行反射以枚举程序集中的所有具体实现。

(其余代码不需要进行其他更改。)

讨论

在stack overflow中有很多问题都是询问IoC容器是否正在替换工厂设计模式。根据我们在这里学到的,工厂模式仍然可以与IoC容器并排使用。然而,工厂模式的角色在上述解决方案中正在发生变化。工厂不再负责创建对象,而只返回作为工厂依赖项注入的对象(因此减少了工厂的含义)。IoC容器负责创建对象并控制它们的生命周期,但处理器工厂内处理器对象的生命周期始终是“单例”,因为它们只从容器注入一次到工厂类。

如果工厂类打算控制处理器的生命周期,那么从容器注入的对象应该被当作处理器模板。通过这种方法,工厂可以通过克隆处理器模板来创建新对象(从而回收工厂的含义)。

还有其他替代解决方案,即将容器而不是处理器集合传递到工厂类中。这样做将允许容器控制工厂返回的处理器的生命周期。

前面描述的解决方案的另一个方面是加入的新方法,在IProcessor中的IsValidUser和它的实现。这有不同的特性。如果切换逻辑基于单个实体,例如enum或原始类型(如int),则最简单的方法是将其实现为属性。使用方法为更复杂的条件检查提供了灵活性,例如,两个或更多个参数检查。因此,方法的方法在某种程度上是更通用的。

也可以不在处理器中使用额外的方法,而是实现其他形式的映射,例如,在上requestType使用属性,甚至将映射视为对工厂类的附加依赖。如果您有兴趣进一步探索,请给我一些评论。

原文地址:https://www.codeproject.com/Articles/1206764/Clean-Factory-Design-Pattern-with-IoC-Container

使用IoC 容器清洁工厂设计模式相关推荐

  1. Spring IOC容器学习总结

    1. Spring Ioc容器 Spring容器是Spring框架的核心.容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁.Spring 容器使用依赖注入(DI)来管理 ...

  2. Spring IoC容器与Bean管理

    Spring IoC容器与Bean管理 一.Spring IoC容器与Bean管理 1.Spring快速入门 IoC控制反转 DI依赖注入 Spring概述 Spring IoC初体验 使用XML方式 ...

  3. Spring4.x(3)---工厂模式设计IOC容器

    工厂模式设计IOC容器 IOC容器的底层实现其实就是利用工厂设计模式.接下来我们通过工厂设计模式模拟一个小型的IOC容器,让大家对IOC的底层原理更加清晰些. 一.搭建案例程序 1)CustomerD ...

  4. 【设计模式】Spring的核心IOC容器中用到的设计模式

    Spring源码(七)-IOC中的那些设计模式 转载于:https://www.cnblogs.com/leiblog/p/10822018.html

  5. [Spring 深度解析]第6章 Spring的IoC容器系列

    6. Spring的IoC容器系列 ​ IoC容器为开发者管理对象之间的依赖关系提供了很多便利和基础服务.有许多IoC容器供开发者选择,SpringFramework的IoC核心就是其中一个,它是开源 ...

  6. 深入理解DIP、IoC、DI以及IoC容器

    对于大部分小菜来说,当听到大牛们高谈DIP.IoC.DI以及IoC容器等名词时,有没有瞬间石化的感觉?其实,这些"高大上"的名词,理解起来也并不是那么的难,关键在于入门.只要我们入 ...

  7. Castle IOC容器实践之TypedFactory Facility(一)

    摘要:相信大家对于Factory Method设计模式都已经不陌生了,在Factory Method中,对于每一个具体的产品都需要有一个与之对应的工厂类,随着具体的产品越来越多,我们对于工厂类的管理就 ...

  8. PHP进阶学习之依赖注入与Ioc容器详解

    背景 在很多编程语言(例如java)开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,一旦有修改,牵扯的类会很多 ...

  9. 从源码深处体验Spring核心技术--基于Xml的IOC容器的初始化

    IOC 容器的初始化包括 BeanDefinition 的 Resource 定位.加载和注册这三个基本的过程. 我们以ApplicationContext 为例讲解,ApplicationConte ...

最新文章

  1. 挨踢人生路--记我的10年18家工作经历 - 后记
  2. linux java maven_Linux——java+tomcat+maven 安装
  3. ASP.NET 发邮件方法
  4. 上海交大 CDNet:基于YOLOv5改进的 人行道 斑马线和汽车过线行为检测
  5. git push origin master报错
  6. 【sock_stream和sock_dgram】、 【AF_INET和AF_UNIX】
  7. 【学术相关】刚刚,中科院最新预警期刊名单发布!
  8. java 事件通知_正确获取Java事件通知
  9. protected default
  10. 解密OpenShift内部通信网络
  11. 一个普通handler会持有activity引用吗_详解handler机制
  12. 计算机考试忘记备注班级了,2012年计算机二级Access第二十五套上机试题及答案详解...
  13. properties配置文件在idea中默认utf-8编码可能会乱码的解决
  14. 寻找春天amp;nbsp;九宫格日记-2014.04.26
  15. EINT DINT ERTM DRTM理解
  16. 3D建模:14个建模小技巧
  17. 「松果圆桌派」花式营销能否助力凉茶打好“翻身仗”?
  18. cacti监控H3C交换机
  19. 折腾了5个多小时的OC启动与win10冲突
  20. 优秀的UI设计师应该了解的图标设计规范!

热门文章

  1. oracle+greatest+max,ORACLE 内置函数之 GREATEST 和 LEAST(求多列的最大值,最小值)
  2. 调节e18-d80nk的测量距离_水准测量基础知识
  3. 喜庆红色C4D立体电商首焦模板|PSD分层格式,设计师大呼真香!
  4. 网页排版规则:你需要知道的
  5. c++判断奇偶_第十一届(今年)蓝桥杯省模拟赛 试题+源码 C/C++详解
  6. Ubuntu系统查看设备的内存信息
  7. Open5GS:开源5G
  8. srsLTE源码学习:RRC:(Radio Resource Control):无线资源控制协议
  9. C语言编写汇编的编译器,用c编写一个asm的编译器
  10. 算法笔记:简单的字符串模式匹配-KMP算法(与BF算法对比时间复杂度)