前端解读控制反转(IOC)

时间:2022-12-03 14:51:14

前言

随着前端承担的职责越来越重,前端应用向着复杂化、规模化的方向发展。大型项目模块化是一种趋势,不可避免模块之间要相互依赖,此外还有很多第三方包。这样的话如何去管理这些繁杂的文件,是一个不可避免的话题。此时作为一种已经被实践证明过的思想模式一直得到大家的青睐,这就是控制反转(IOC)。

IOC定义

先看一下*上的定义:

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

原则

  1. 高层模块不应该依赖低层模块。两个都应该依赖抽象
  2. 抽象不应该依赖具体实现
  3. 面向接口编程,而非面向实现编程

针对前端来说,接口的概念不那么清晰明了,不像强类型语言。

概念是比较枯燥的,下面结合例子来看一下可能更好理解一点。

目的

根据概念可以看到最主要的目的就是降低耦合,提高扩展性。在深究之前,我们先看下代码耦合

代码耦合

所谓耦合,可以如下图显示:

前端解读控制反转(IOC)

比较清晰明了,代码相互之间的联系太直接:

假如obj2报错,那么整个系统也都报错了。

所以我们的目的就是降低二者之间的耦合度,

结合图来说比较清晰,

如果两者不这么直接的发生关系,那么相互影响的概率就小了那么多了。

另外,这是比较少的模块,常规项目里显然不仅仅是只有这么少,想象一下多个模块的场景:

前端解读控制反转(IOC)

这里除了耦合之外,不同齿轮之间的依赖关系也是个头疼的问题,迭代个几个版本之后发现,这是什么东西,一动就有bug。。。。

所以IOC就是来解决上述问题的。

其常见方式是依赖注入和依赖查找。在js领域里面最出名的就是angular中大量使用了依赖注入。文字比较苍白,我们可以通过例子来看看。

实例

就从nba来说,有那么一些球星,我们想知道他所属的球队,那么可能就像下面这个情况:

//球队信息
class RTeam {
constructor(){
this.name = '火箭'
}
}
// 球员信息
class Player{
constructor(){
this.team = new Team()
}
info(){
console.log(this.team.name)
}
}
// 球员ym
let ym = new Player()
ym.info() // ‘火箭’

看起来挺好的,球员player依赖于某个球队RTeam

当调用的时候主动去加载球队即可。此时的控制权在player这里。

假如这个时候,球员发生交易了,球队信息更换了,转换到team2了。

这时候我们就需要去修改player里的代码了,因为球员那里直接写死了对RTeam的依赖,这种可扩展性是很差的。

这不是我们所想要的,需要重新思考下依赖关系处理了。

球员和球队之间非得这么直接粗暴的发生联系吗,

一个球员对应一个球队的话,未来会发生变化的可能性太大了,毕竟不止一个球队。

如果两者之间不直接发生联系,中间就需要一个中间模块来负责两者关系的处理

球员不关注球队从哪来,只要给到我就行了。

这样控制权就不是直接落在player这里了,这正是IOC的设计思路。

依据IOC 改进

参照IOC的几条原则,我们进行下改进。

  1. 高层模块不应该依赖低层模块。两个都应该依赖抽象

    这里player是高层模块,直接依赖了球队这个低级模块。所以我们将两者解耦,player不再直接依赖于该team这个class

  2. 抽象不应该依赖具体实现,具体实现应该依赖抽象

    具体到这里来看我们的player模块不应该直接依赖具体team,而是通过构造函数将抽象的teaminfo实例传递进去,这样就解耦具体实现。

直接看代码比较清楚:

// 球队信息不依赖具体实现
// 面向接口即面向抽象编程
class TeamInfo {
constructor(name) {
this.name = name
}
}
class Player {
// 此处的参数,是teamInfo的一个实例,不直接依赖具体的实例
// 面向抽象
constructor(team) {
this.team = team
}
info() {
console.log(this.team.name)
}
}
// 将依赖关系放到此处来管理,控制权也放到此处
// Player和TeamInfo之间不再有直接依赖
// 原本直接掌握teaminfo控制权的player不再直接依赖
// 将依赖控制,落在此处(第三方模块专门管理)即为控制反转
var ym = new Player(new TeamInfo('火箭'))
ym.info()
var kobe = new Player(new TeamInfo('湖人'))
kobe.info()

这里发现,TeamInfo和Player之间已经没有直接关联了,依赖关系统一放到getTeamInfo中。

所谓控制反转就如何上面一样,将依赖的控制权由player转移到其他地方即我们专门的依赖管理来做了。

这样再增加一个team3,改动也不大,复用就行了。

其中之间的关系,如下面这个图:

前端解读控制反转(IOC)

彼此不直接发生联系,依赖关系统一在中间模块来管理,更加清晰。

实现

上面其实就是最简单的IOC实现了,基于IOC的编程思想,主要有两种实现方式:依赖注入和依赖查找。依赖查不太常用,常见的是依赖注入。

依赖注入

在js中常见的就是依赖注入。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中。

在RequireJS/AMD的模块加载器的实现就是基于依赖注入来的,还有大名鼎鼎的angular,其实现也使用了大量的依赖注入。

结束语

关于控制反转,一句话总结:控制反转这里控制权从使用者本身转移到第三方容器上,而非是转移到被调用者上,这里需要明确不要疑惑。控制反转是一种思想,依赖注入是一种设计模式。

可能听起来比较抽象,其实我们平时开发中见到和用到的也是蛮多的,可能原来没有对应起来罢了。

至于依赖注入,前端领域用到的就更多了,下面我将结合自身实践翻译一篇个人认为很好的文章Dependency-injection-in-JavaScript,来进一步深入依赖注入。

至此,个人见解分享完毕,抛砖引玉,希望共同学习进步。

前端解读控制反转(IOC)的更多相关文章

  1. 前端理解控制反转ioc

    工作一直都是写前端,而且都是偏业务的.相关的框架代码层面的了解还是有很大的缺失.一直想多写些维护性,可读性强的代码. 这段时间对控制反转ioc,这样的设计有了一个初步的了解. 前端为弱语言,平时代码的 ...

  2. 20181123_控制反转(IOC)和依赖注入(DI)

    一.   控制反转和依赖注入: 控制反转的前提, 是依赖倒置原则, 系统架构时,高层模块不应该依赖于低层模块,二者通过抽象来依赖 (依赖抽象,而不是细节) 如果要想做到控制反转(IOC), 就必须要使 ...

  3. 控制反转IoC简介

    控制反转IoC简介 在实际的应用开发中,我们需要尽量避免和降低对象间的依赖关系,即降低耦合度.通常的业务对象之间都是互相依赖的,业务对象与业务对象.业务对象与持久层.业务对象与各种资源之间都存在这样或 ...

  4. 浅析“依赖注入(DI)/控制反转(IOC)”的实现思路

    开始学习Spring的时候,对依赖注入(DI)——也叫控制反转(IOC)—— 的理解不是很深刻.随着学习的深入,也逐渐有了自己的认识,在此记录,也希望能帮助其他入门同学更深入地理解Spring.本文不 ...

  5. 控制反转IOC的依赖注入方式

    引言: 项目中遇到关于IOC的一些内容,因为和正常的逻辑代码比较起来,IOC有点反常.因此本文记录IOC的一些基础知识,并附有相应的简单实例,而在实际项目中再复杂的应用也只是在基本应用的基础上扩展而来 ...

  6. 控制反转IOC与依赖注入DI

    理解 IOC  http://www.cnblogs.com/zhangchenliang/archive/2013/01/08/2850970.html IOC 相关实例      的http:// ...

  7. 控制反转(Ioc)和依赖注入(DI)

    控制反转IOC, 全称 “Inversion of Control”.依赖注入DI, 全称 “Dependency Injection”. 面向的问题:软件开发中,为了降低模块间.类间的耦合度,提倡基 ...

  8. 控制反转IOC与依赖注入DI【转】

    转自:http://my.oschina.net/1pei/blog/492601 一直对控制反转.依赖注入不太明白,看到这篇文章感觉有点懂了,介绍的很详细. 1. IoC理论的背景我们都知道,在采用 ...

  9. 依赖注入(DI)和控制反转(IOC)

    依赖注入(DI)和控制反转(IOC) 0X1 什么是依赖注入 依赖注入(Dependency Injection),是这样一个过程:某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只 ...

随机推荐

  1. Freemark笔记

    Freemark基本语法知识 Freemark 常用代码总结1 Freemark 常用代码总结2 笔记,吐槽一下freemark的蛋疼语法. 1.elseif 中间不能有空格 2.三目运算符 语法和j ...

  2. 几种任务调度的 Java 实现方法与比较

    综观目前的 Web 应用,多数应用都具备任务调度的功能.本文由浅入深介绍了几种任务调度的 Java 实现方法,包括 Timer,Scheduler, Quartz 以及 JCron Tab,并对其优缺 ...

  3. Android 插件化 动态升级

    最新内容请见原文:Android 插件化 动态升级 不少朋友私信以及 Android开源交流几个 QQ 群 中都问到这个问题,这里简单介绍下 1.作用 大多数朋友开始接触这个问题是因为 App 爆棚了 ...

  4. linux前景到底怎么样啊?

    我就不长篇大论,举四个例子你看看. 1.目下最热最潮最流行的云计算技术的背后是虚拟化和网格技术,而虚拟化和网格技术基本是Linux的天下,目前虚拟化的三大家:Vmware,Xen,Hyper-V中,市 ...

  5. 89. Gray Code

    题目: The gray code is a binary numeral system where two successive values differ in only one bit. Giv ...

  6. Oracle DB 自动管理共享内存

    • 启用Oracle Enterprise Manager (EM) 内存参数 • 设置自动优化的内存参数 • 使用手动优化的SGA 参数覆盖最小大小 • 使用SGA Advisor 设置SGA_TA ...

  7. jquery validation插件使用

    首先需要引入jQuery.js和jquery.validate.js 以下面代码为例: <form id="mainform"> <fieldset> &l ...

  8. Linux 安装依赖库

    ###安装依赖库###yum -y install rsync net-snmp syslog net-snmp-devel wget patch screen gcc gcc-c++ autocon ...

  9. 关于table表格 td里内容较多换行的处理方法

    最近在用table的时候由于td内容较多默认换行了,很不美观.于是找到处理方法: 在声明table的时候添加一个样式: <table id="tbOffice" data-r ...

  10. LeetCode 9&period; Palindrome Number(c语言版)

    题目: Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same ...