0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何采用IoC实现对应用程序的流程控制

454398 来源:博客园 作者:蒋金楠 2020-10-29 11:21 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

我之前写过一系列关于.NET Core依赖注入的文章,由于.NET Core依赖注入框架的实现原理发生了很大的改变,加上我对包括IoC和DI这些理论层面的东西又有了一些新的理解。

软件设计中由一些所谓的理念都没有一个明确的定义,比如之前流行的SOA和现在炒的火热的微服务(Micro Service)和无服务器(Serverless),我们都不能通过一个明确的“内涵”给它们一个准确地定义,只能从“外延”上描述这些架构设计应该具有怎样的特性。正因为无法给出一个明确的界定,造成了人们针对同一个概念出现了很多不同的理解。针对IoC也是这种情况,所以本章所诉的仅仅代表作者的一家之言,读者朋友姑妄听之,仅作参考。

一、流程控制的反转

我听到很多人将IoC说成是一种“面向对象的设计模式”,但在我个人看来IoC不能算作 一种“设计模式”,其自身也与“面向对象”没有直接的关系。我觉得很多人之所以不能很准确地理解IoC源于他们忽略了一个最根本的东西,那就是IoC这个短语,也就是他们之所以对IoC产生了诸多误解是因为他们忽略了IoC的定义。

IoC的全名Inverse of Control,翻译成中文就是“控制反转”或者“控制倒置”。控制反转也好,控制倒置也罢,它体现的意思是控制权的转移,即原来控制权在A手中,现在需要B来接管。那么具体对于软件设计来说,IoC所谓的控制权的转移具有怎样的体现呢?要回答这个问题,就需要先了解IoC的C(Control)究竟指的是怎样一种控制。对于我们所在的任何一件事,不论其大小,其实可以分解成相应的步骤,所以任何一件事都有其固有的流程,IoC涉及的所谓控制可以理解为“针对流程的控制”。

我们通过一个具体事例来说明传统的设计在采用了IoC之后针对流程的控制是如何实现反转的。比如说现在设计一个针对Web的MVC类库,我们不妨将其命名为MvcLib。简单起见,这个类库中只包含如下这个同名的静态类。

public static class MvcLib

{
    public static Task ListenAsync(Uri address);
    public static Task ReceiveAsync();
    public static Task CreateControllerAsync(Request request);
    public static Task ExecuteControllerAsync(Controller controller);
    public static Task RenderViewAsync(View view);
}

MvcLib提供了如上5个方法帮助我们完成整个HTTP请求流程中的5个核心任务。具体来说,ListenAsync方法启动一个监听器并将其绑定到指定的地址进行HTTP请求的监听,抵达的请求通过ReceiveAsync方法进行接收,我们将接收到的请求通过一个Request对象来表示。CreateControllerAsync方法根据接收到的请求解析并激活请求的目标Controller对象。ExecuteControllerAsync方法执行激活的Controller并返回一个表示视图的View对象。RenderViewAsync最终将View对象转换成HTML并作为当前请求响应的内容返回给请求的客户端。

现在我们在这个MvcLib的基础上创建一个真正的MVC应用,那么除了按照MvcLib的规范自定义具体的Controller和View之外,我们还需要自行控制从请求的监听与接收、Controller的激活与执行以及View的最终呈现在内的整个流程,这样一个执行流程反映在如下所示的代码中。

class Program

{
    static async Task Main()
    {
         Uri address = new Uri("http://0.0.0.0:8080/mvcapp");
         await MvcLib.ListenAsync(address);
         while (true)
        {
            var request = await MvcLib.ReceiveAsync();
            var controller = await MvcLib.CreateControllerAsync(request);
            var view = await MvcLib.ExecuteControllerAsync(controller);
            await MvcLib.RenderViewAsync(view);
        }
    }    
}

这个例子体现了如图1所示的流程控制方式(应用的代码完全采用异步的方式来处理请求,为了让流程图显得更加简单,我们在流程图中画成了同步的形式,读者不必纠结这个问题)。我们设计的类库(MvcLib)仅仅通过API的形式提供某种单一功能的实现,作为类库消费者的应用程序(App)则需要自行编排整个工作流程。如果从重用的角度来讲,这里被重用的仅限于实现某个环节单一功能的代码,编排整个工作流程的代码并没有得到重用。

图1 流程控制掌握在应用程序手中

但是当我们构建一个应用的时候,我们需要的不仅仅是一个能够提供单一API的类库,我们希望的理想形式是能够直接在一个现有的框架上构建我们的应用。类库(Library)和框架(Framework)的不同之处在于,前者往往只是提供实现某种单一功能的API,而后者则针对一个目标任务对这些单一功能进行编排形成一个完整的流程,这个流程在一个引擎的驱动下自动执行。

对于我们上面演示MvcLib来说,作为消费者的应用程序需要自行控制整个HTTP请求的处理流程,但这是实际上这是一个很“泛化”的工作流程,几乎所有的MVC应用均采用这样的流程监听、接收请求并最终对请求予以响应。如果我们将这个流程实现在一个MVC框架之中,由它构建的所有MVC应用就可以直接使用这个请求处理流程,而不需要自行重复实现它。

现在我们将MvcLib从类库改造成一个框架,并姑且将其称为MvcFrame。如图2所示,MvcFrame的核心是一个被称为MvcEngine的执行引擎,它驱动一个编排好的工作流对HTTP请求进行一致性处理。如果我们利用MvcFrame构建一个具体的MVC应用,除了根据我们的业务需求定义相应的Controller和View之外,我们只需要初始化这个引擎并直接启动它即可。如果你曾经开发过ASP.NET MVC应用,你会发现ASP.NET MVC就是这么一个框架。

图2 流程控制反转到框架手中

有了上面演示的这个例子作为铺垫,我们应该很容易理解IoC所谓的控制反转。总的来说,IoC是我们设计框架所采用的一种基本思想,所谓的控制反转就是将对应用流程的控制转移到框架中。拿上面这个例子来说,在传统面向类库编程的时代,针对HTTP请求处理的流程牢牢控制在应用程序手中。在引入框架之后,请求处理的控制权转移到了框架手上。

二、好莱坞法则

在好莱坞,把简历递交给演艺公司后就只有回家等待。由演艺公司对整个娱乐项目的完全控制,演员只能被动式的接受电影公司的工作,在需要的环节中,完成自己的演出。“不要给我们打电话,我们会给你打电话(don‘t call us, we‘ll call you)”这是著名的好莱坞法则( Hollywood Principle或者 Hollywood Low),IoC完美地体现了这一法则。

图3 好莱坞法则

在IoC的应用语境中,框架就像是掌握整个电影制片流程的电影公司,由于它是整个工作流程的实际控制者,所以只有它知道哪个环节需要哪些组件。应用程序就像是演员,它只需要按照框架定制的规则注册这些组件就可以了,因为框架会在适当的时机字典加载并执行注册的组件。

以熟悉的ASP.NET Core MVC或者ASP.NET MVC应用开发来说,我们只需要按照约定规则(比如目录结构和命名等)定义相应的Controller类型和View文件就可以了。当ASP.NET (Core )MVC框架在进行处理请求的过程中,它会根据解析生成的路由参数定义为对应的Controller类型,并按照预定义的规则找到我们定义的Controller,然后自动创建并执行它。如果定义在当前Action方法需要呈现一个View,框架自身会根据预定义的目录约定找到我们定义的View文件,并对它实施动态编译和执行。整个流程处处体现了“框架Call应用”的好莱坞法则。

总的来说,我们在一个框架的基础上进行应用开发,就相当于在一条调试好的流水线上生成某种商品,我们只需要在相应的环节准备对应的原材料,最终下线的就是我们希望得到的最终产品。IoC几乎是所有框架均具有的一个固有属性,从这个意义上讲,“IoC框架”的说法其实是错误的,世界上并没有什么IoC框架,或者说几乎所有的框架都是IoC框架。

三、流程定制

我们采用IoC实现了流程控制从应用程序向框架自身的反转,但是这个被反转的仅仅是一个泛化的流程,任何一个具体的应用都可能需要对组成该流程的某些环节进行定制。还是以我们的MVC框架来说,可能默认的请求处理流程只考虑到针对HTTP 1.1的支持,但是当我们在设计框架的时候应该提供相应的扩展点来支持HTTP 2。作为一个Web框架,用户认证功能是必备的,但是框架自身不能限制于某一种或者几种固定的认证方式,应该通过扩展的方式让用户可以自由地定制任意的认证模式。

我们可以说得更加宽泛点。如图4所示,我们将一个泛化的工作流程(A=>B=>C)被定义在框架之中,建立在该框架的两个应用需要对组成这个流程的某些环节进行定制。比如步骤A和C可以被App1重用,但是步骤B却需要被定制(B1),App2则重用步骤A和B,但是需要按照自己的方式处理步骤C。

图4 应用程序对流程的定制

IoC将对流程的控制从应用程序转移到框架之中,框架利用一个引擎驱动整个流程的执行,应用程序无需关心该工作流程的细节,它只需要启动这个引擎即可。但是这个引擎一旦被启动,框架就会完全按照预先编排好的流程进行工作,如果应用程序希望整个流程按照自己希望的方式被执行,针对流程的定制一般在发生在启动引擎之前。

一般来说,框架会以相应的形式提供一系列的扩展点,应用程序则通过定义扩展的方式实现对流程某个环节的定制。在引擎被启动之前,应用程序将所需的扩展注册到框架之中。一旦引擎被正常启动,这些注册的扩展会自动参与到整个流程的执行过程中。

综上所述,IoC一方面通过流程控制从应用程序向框架的反转实现了针对流程自身的重用,另一方面通过内置的扩展机制这个被重用的流程可能自由地被定制,这两个因素决定了框架自身的价值。重用让框架不仅仅是为应用程序提供实现单一功能的API,而是提供一整套可执行的解决方案,可定制则使我们可以为不同的应用程序对框架进行定制,这无疑让框架可以使用到更多的应用之中。
编辑:hfy

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 无服务器
    +关注

    关注

    0

    文章

    18

    浏览量

    4195
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    S32K系列引导加载程序应用程序跨不同定制电路板设计的跳转问题求解

    我在两个自定义S32K358板上实现引导加载程序时遇到了问题,将不胜感激您的见解。 **设置:** - 两块板使用相同的S32K358微控制器 - 板 1:引导加载程序正常运行 - 成
    发表于 04-22 07:02

    RDMA设计56:如何设计基于RDMA的应用程序

    工作流程图 在接收到 FPGA 数据包后,应用程序进行数据包类型判断,针对 SEND 数据包和 WRITE 数据包将分别进入对应的处理流程。 当接收到 SEND 数据包后,将首先记录首
    发表于 04-05 09:54

    如何构建蓝牙应用程序

    应用程序使用蓝牙(blueZ)。 我已经安装了 gcc-riscv64-linux-gnu。 但是,没有安装 blueZ 标头和库。 如何构建我的蓝牙应用程序
    发表于 04-01 07:31

    利用XStream Browser加快示波器程控设计

    所有基于 Windows 系统的TeledyneLeCroy “XStream” 系列仪器均完全支持基于微软组件对象模型(COM)的自动化接口控制。通过 COM 技术,控制应用程序可直接在仪器上运行
    的头像 发表于 01-24 11:32 5613次阅读
    利用XStream Browser加快示波器<b class='flag-5'>程控</b>设计

    什么是WiFi远程控制模块?技术特点和应用场景有哪些?

    便捷和高效。无论是通过手机APP、电脑终端,还是智能语音助手,WiFi远程控制模块都能够帮助用户实现实时、远程操作,提升生活质量与工作效率。 什么是WiFi远程控制模块? WiFi远程控制
    的头像 发表于 11-29 14:10 706次阅读
    什么是WiFi远<b class='flag-5'>程控制</b>模块?技术特点和应用场景有哪些?

    电能质量在线监测装置的备用链路切换机制是否支持远程控制

    现代电能质量在线监测装置的备用链路切换机制 普遍支持远程控制 ,主流厂商通过协议指令、软件平台和硬件冗余设计,实现了从链路状态查询、策略配置到强制切换的全流程远程操作。以下是技术实现
    的头像 发表于 11-06 16:48 1604次阅读

    PYQT 应用程序框架及开发工具

    大家好,本团队此次分享的内容为开发过程中使用到的PYQT 应用程序框架及开发工具。 pYqt 是一个多平台的 python 图形用户界面应用程序框架,由于其面向对象、 易扩展(可实现组件编程等
    发表于 10-29 07:15

    信号发生器远程控制LabVIEW自动化方法技巧

    信号发生器在现代电子工程与测试测量中扮演着重要角色,而通过LabVIEW实现其远程控制,则进一步提高了测试的灵活性和效率。以下是几种关键的自动化方法技巧,以帮助工程师们更好地实现这一目标。   首先
    的头像 发表于 09-23 18:05 807次阅读
    信号发生器远<b class='flag-5'>程控制</b>LabVIEW自动化方法技巧

    NVMe高速传输之摆脱XDMA设计28: TLP 事务处 理程序的执行流程

    程序的执行流程图当对应任务接口的事务缓存中存在未处理事务时, 处理程序从缓存中获取事务。首先检查事务类型, 当事务类型为 Cpl 响应类型事务时, 如果当前
    发表于 09-21 08:51

    学生适合使用的SOLIDWORKS 云应用程序

    随着科技的不断发展,计算机辅助设计(CAD)技术已经成为现代工程教育的重要组成部分。SOLIDWORKS作为一款CAD软件,其教育版云应用程序为学生提供了强大而灵活的设计平台。本文将探讨
    的头像 发表于 09-15 10:39 952次阅读
    学生适合使用的SOLIDWORKS 云<b class='flag-5'>应用程序</b>

    宏集方案 | 如何选择适合您的过程控制器?

    在现代工业中,过程控制器是确保生产效率、质量和安全性的关键设备。它们可以精准监测温度、湿度等变量,优化制造流程,减少人工干预,从而降低错误率和运营成本。但您是否清楚,哪种过程控制器更适合您的企业
    的头像 发表于 08-08 18:12 534次阅读
    宏集方案 | 如何选择适合您的过<b class='flag-5'>程控制</b>器?

    FX3 UVC 无法与 Ubuntu 24.04 Cheese 或 Snapshot 相机应用程序配合使用,怎么处理?

    当我尝试使用 Cheese 或 Snapshot 应用程序将未压缩的 1080p30 从我的 FX3 UVC+UAC 设备流式传输到 Ubuntu 24.04 机器时遇到问题。我的 FX3 在
    发表于 07-16 06:37

    告别布线烦恼!御控智能网关实现工业PLC无线远程控制终极指南

    工厂设备PLC布线复杂、改造困难、移动受限,御控工业智能网关,无需挖沟铺线,轻松实现工业自动化PLC无线远程控制!让设备操控自由无界,运维效率飞跃提升!
    的头像 发表于 07-09 16:15 827次阅读

    是德示波器MSOX3054T远程控制自动化测试

    实现自动化测试,助力测试流程的智能化升级。   一、MSOX3054T的核心优势:远程控制的基础 MSOX3054T示波器具备出色的信号采集与分析能力,其高频带宽、高采样率及深存储深度,使其适用于复杂信号的精确测量。而远
    的头像 发表于 07-08 17:09 756次阅读
    是德示波器MSOX3054T远<b class='flag-5'>程控制</b>自动化测试

    三菱PLC数据采集实现变频器远程监控与远程控制

    在现代自动化工业领域中,PLC控制变频器能够实现对生产电机的精准控制。通过通信接口,工业智能网关能够读取和写入各项数据,从而会实现对变频器的远程监控与远
    的头像 发表于 07-08 14:30 1597次阅读
    三菱PLC数据采集<b class='flag-5'>实现</b>变频器远程监控与远<b class='flag-5'>程控制</b>