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

    文章

    16

    浏览量

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

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    如何使用无线远程控制模块来实现rs-485无线控制

    无线远程控制模块,是一种在工业自动化、远程监控等领域广泛应用的技术。以下将主要介绍无线远程控制模块及其在实现485无线控制中的应用。 一、无线远程控
    的头像 发表于 04-24 17:08 ?511次阅读
    如何使用无线远<b class='flag-5'>程控制</b>模块来<b class='flag-5'>实现</b>rs-485无线<b class='flag-5'>控制</b>?

    如何选择适合您的过程控制器?

    在现代工业中,过程控制器是确保生产效率、质量和安全性的关键设备。它们可以精准监测温度、湿度等变量,优化制造流程。但您是否清楚如何选择合适的过程控制器?
    的头像 发表于 04-18 17:54 ?345次阅读
    如何选择适合您的过<b class='flag-5'>程控制</b>器?

    高速ssd存储系统中数据缓存控制流程控制设计

    高速SSD系统中流程控制模块设计。该模块主要由寄存器、读状态机、写状态机和命令生成模块组成,系统介绍各模块功能。
    的头像 发表于 04-14 10:43 ?352次阅读
    高速ssd存储系统中数据缓存<b class='flag-5'>控制</b>器<b class='flag-5'>流程控制</b>设计

    智慧路灯如何实现程控制

    引言 在智慧城市建设的进程中,叁仟智慧路灯作为重要的基础设施,其远程控制功能发挥着关键作用。远程控制使得叁仟智慧路灯能够摆脱地域限制,实现高效、精准的管理,极大地提升了城市照明系统的运行效率与智能化
    的头像 发表于 03-18 12:27 ?393次阅读
    智慧路灯如何<b class='flag-5'>实现</b>远<b class='flag-5'>程控制</b>?

    AWTK-WEB 快速入门(5) - C 语言 WebSocket 应用程序

    导读WebSocket可以实现双向通信,适合实时通信场景。本文介绍一下使用C语言开发AWTK-WEB应用程序,并用WebSocket与服务器通讯。用AWTKDesigner新建一个应用程序先安装
    的头像 发表于 02-19 11:49 ?527次阅读
    AWTK-WEB 快速入门(5) - C 语言 WebSocket <b class='flag-5'>应用程序</b>

    程控水冷负载解析

    程控水冷负载是一种通过计算机程序控制水冷系统对特定负载进行冷却的技术,以下是关于它的解析: 基本原理 阻性负载产热 :许多电气设备如变压器、电机、变频器等在工作过程中,电流通过导线和线圈时因电阻损耗
    发表于 02-18 16:04

    plc远程控制模块是什么

    PLC远程控制模块是什么?PLC(ProgrammableLogicController,可编程逻辑控制器)远程控制模块是用于实现远程监控和控制
    的头像 发表于 02-12 17:20 ?842次阅读

    AWTK-WEB 快速入门(1) - C 语言应用程序

    导读AWTK可以使用相同的技术栈开发各种平台的应用程序。有时我们需要使用Web界面与设备进行交互,本文介绍一下如何使用C语言开发AWTK-WEB应用程序。用AWTKDesigner新建一个应用程序
    的头像 发表于 11-27 11:46 ?804次阅读
    AWTK-WEB 快速入门(1) - C 语言<b class='flag-5'>应用程序</b>

    使用树莓派实现程控制的技巧

    树莓派是一款功能强大的微型计算机,其体积小巧、价格低廉,非常适合用于各种DIY项目。其中,远程控制是树莓派应用中非常受欢迎的一个领域。通过远程控制,我们可以随时随地访问和管理树莓派,实现数据监控
    的头像 发表于 11-11 11:37 ?1545次阅读

    程控制温控器的应用

    连接到用户的智能手机或其他移动设备。用户可以通过专门的应用程序远程监控和调节家中的温度。这些温控器通常与家中的中央供暖和制冷系统相连,能够根据用户的设定自动调节室内温度。 远程控制温控器的优势 节能高效 :用户可以根
    的头像 发表于 11-06 13:47 ?1244次阅读

    普通空开怎样远程控制断电

    程控制断电技术的应用场景非常广泛,包括但不限于: 智能家居系统 :用户可以通过手机应用或语音助手远程控制家中的电器,实现节能和便捷。 工业自动化 :在生产线上,远程控制断电可以快速
    的头像 发表于 10-17 14:02 ?2795次阅读

    嵌入式学习-飞凌嵌入式ElfBoard ELF 1板卡-shell脚本编写之流程控制

    1、条件语句shell语句的流程控制与C语言不一样,流程控制中不能为空。shell中if语法如下,其中confition表示条件判断式,command为程序段落。if else语法
    发表于 09-05 09:06

    所有的labview应用程序的三要素是什么

    的一种图形化编程语言,它广泛用于数据采集、仪器控制、自动化测试和过程控制等领域。LabVIEW应用程序通常由三个基本要素组成:前面板(Front Panel)、块图(Block Diagram)和图标
    的头像 发表于 09-04 16:08 ?950次阅读

    飞凌嵌入式ElfBoard ELF 1板卡-shell脚本编写之流程控制

    1、条件语句 shell语句的流程控制与C语言不一样,流程控制中不能为空。 shell中if语法如下,其中confition表示条件判断式,command为程序段落。 if else语法
    发表于 09-04 10:12

    android 远程控制如何实现

    在现代工作和生活中,远程控制安卓设备或使用安卓设备远程控制其他设备已成为常见需求。安卓远程控制允许IT管理员远程访问安卓设备。实施远程控制应用程序
    的头像 发表于 08-21 18:05 ?1535次阅读
    android 远<b class='flag-5'>程控制</b>如何<b class='flag-5'>实现</b>