使用 IoC 反转控制的三种设计模式
来源:互联网 发布:feeling软件 编辑:程序博客网 时间:2024/05/24 02:37
使用 IoC 反转控制的三种设计模式
对于许多开发人员来说,控制反演(IoC)都是一个模糊的概念,因为他们在现实世界中很少或没有被应用过。在最好的情况下,控制反演(IoC)可以加单的认为是等效于依赖注入(DI)。实际上,只有在翻转控制与依赖注入双方都只是反映翻转依赖管理控制的时候,才认为两者是等效的。虽然,依赖注入实际上是IoC的一种众所周知的形式。但是,事实上IoC却是一个相对更为广泛的软件设计范例,可以通过多种模式来进行实现。在本文中,我们将介绍依赖注入,观察者模式和模板方法模式如何实现控制反转的。
IOC范式揭秘
控制反转是一种带有某些特征的模式。下面,给出了由Martin Fowler给出的一个IOC经典范例,该范例实现的功能是从控制台中收集用户数据。
public static void main(String[] args) { while (true) { BufferedReader userInputReader = new BufferedReader( new InputStreamReader(System.in)); System.out.println("Please enter some text: "); try { System.out.println(userInputReader.readLine()); } catch (IOException e) { e.printStackTrace(); } }}
这种情况下,控制已经被有效的反转了。
从更通用的角度来看,由框架定义的每个可调用扩展点(以接口实现,实现继承(也称为子类)的形式)是IoC的一种明确定义的形式。
看下,下述这个简单的Servlet例子:
public class MyServlet extends HttpServlet { protected void doPost( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // developer implementation here } protected void doGet( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // developer implementation here }}
使用那些通过提供可扩展API,秉承开闭原则的框架时,使用框架的开发人员的角色,最终被归结为定义自己的一组自定义类,即开发人员要么通过实现框架提供的一个或多个接口方式,要么通过继承现有基类的方式。反过来,类的实例却是直接框架进行实例化,并且这些事例是被框架调用的。
此处引用Fowler的话:
该框架调用开发人员,而不是开发人员调用该框架。
因此,IoC通常被称为好莱坞原则:
UserQueue
接口定义了公共的API,用于在一个队列中去存放User对象(为了简单明了,此处忽略User的具体实现)。AbstractUserQueue则是为后续的继承类,提供了一些公用的方法实现。最后的UserFifoQueue
和 UserLifoQueue,则是分别实现了FIFO 和 LIFO 队列。
这是,实现子类多态性的一种有效方式。但是这具体用什么来买我们好处呢?实际上,好处还是蛮多的。
通过创建一个依赖于UserQueue抽象类型(也称为DI术语中的服务)的客户端类,可以在运行时注入不同的实现,无需会重构使用客户端类的代码:
该类在构造函数中声明对抽象类 UserQueue
的依赖。也就是说,依赖关系不再通过 在构造函数中使用 new 操作, 相反,通过外部注入的方式,要么使用依赖注入框架(如CDI和谷歌的Guice),要么使用factory或builders模式。
简而言之,使用DI,客户端类的依赖关系的控制,不再位于这些类中;而是在注入器中进行:
观察者模式实现IOC
直接通过观察者模式实现IOC,也是一种常见的直观方式。广义上讲,通过观察者实现IOC,与前文提到的通过GUI界面中的action监听器方式类似。但是在使用action监听器情况下,只有在特定的用户事件发生时(点击鼠标,键盘或窗口事件等),才会发生调用。观察者模式通常用于在模型视图的上下文中,跟踪模型对象的状态的变迁。
在一个典型的实现中,一到多个观察者绑定到可观察对象(也称为模式术语中的主题),例如通过调用addObserver方法进行绑定。一旦定义了被观察者和观察者之间的绑定,则被观察者状态的变迁都会触发调用观察者的操作。
User类中,当通过setter方法变更其状态事,都会触发调用绑定到它的观察者。
使用主题观察者和主题,以下是实例给出了观察方式:
public static void main(String[] args) { User user = new User("John"); user.addObserver(() -> System.out.println( "Observable subject " + user + " has changed its state.")); user.setName("Jack");}
每当User对象的状态通过setter方法进行修改时,观察者将被通知并向控制台打印出一条消息。到目前为止,给出了观察者模式的一个简单用例。不过,通过这个看似简单的用例,我们了解到在这种情况下控制是如何实现反转的。
通过模板方法模式实现IoC
模板方法模式实现的思想是在一个基类中通过几个抽象方法(也称算法步骤)来定义一个通用的算法,然后让子类提供具体的实现,这样保证算法结构不变。
我们可以应用这个思想,定义一个通用的算法来处理领域实体:
public abstract class EntityProcessor { public final void processEntity() { getEntityData(); createEntity(); validateEntity(); persistEntity(); } protected abstract void getEntityData(); protected abstract void createEntity(); protected abstract void validateEntity(); protected abstract void persistEntity();}
这也是 IoC 的典型例子,通过分层结构实现。这种情况下,模板方法只是可调的扩展点的一个漂亮的名字,被开发者用来管理自己的一系列实现。
来自作者更多的文章
- Validate Object Graphs with Java Bean Validation's @Valid Annotation
- Java Bean Validation's validateProperty() and validateValue() in Three Minutes
总结
尽管控制反转普遍存在于 Java 的生态系统中,特别是很多框架普遍采用了依赖注入,但对于多数开发者来说,这个模式仍然很模糊,对其应用也受限于依赖注入。在这篇文章中,我展示了几种实际可用的实现 IoC 的方法,阐明了这一概念。
依赖注入:从客户端获得依赖关系的控制不再存在于这些类中。它存由底层的注入器 / DI 框架来处理。
观察者模式:当主体发生变化时,控制从观察者传递到主体。
模板方法模式:控制发生在定义模板方法的基类中,而不是实现算法步骤的子类中。
像往常一样,怎样以及何时使用 IoC 是通过对每个用例的分析来决定的,不要为了 IoC 而 IoC。
- 使用 IoC 反转控制的三种设计模式
- 使用 IoC 反转控制的三种设计模式
- 使用 IoC 反转控制的三种设计模式
- 使用 IoC 反转控制的三种设计模式
- 控制反转 (IOC) 设计模式
- spring IOC控制反转及IOC实现的三种方式和bean标签使用
- 设计模式之反转控制(IOC)
- 控制反转(Ioc)的设计原则
- 控制反转(Ioc)的设计原则
- 控制反转(Ioc)的设计原则
- 关于IoC控制反转的设计原则
- 关于IoC控制反转的设计原则
- 控制反转(Ioc)的设计原则
- Spring实现控制反转(IOC)的三种方式(零)——理解IOC
- android设计模式之控制反转(IOC)原则
- php设计模式-Ioc(控制反转)和Di(依赖注入)
- 控制反转(IoC) ? 工厂模式?
- 控制反转(IoC) ? 工厂模式?
- vue项目中的mock data
- [机器学习入门] 李宏毅机器学习笔记-12 (Why Deep Learning? ; 为什么是深度学习?)
- #3 给路由分配模型
- python安装科学计算拓展库numpy失败原因及解决方案
- Python基础(六)- 函数
- 使用 IoC 反转控制的三种设计模式
- hihoCoder1044— 状态压缩·一(状压dp)
- python cookbook学习笔记十六:类和对象(1)
- android 对sqlite数据库的增删改查
- 明天的要看的知识
- freemaker 笔记
- Python3.X 爬虫实战(静态下载器与解析器)
- JavaScript 的void关键字
- 二分法查找