前端解读控制反转(IOC)
前言
随着前端承担的职责越来越重,前端应用向着复杂化、规模化的方向发展。大型项目模块化是一种趋势,不可避免模块之间要相互依赖,此外还有很多第三方包。这样的话如何去管理这些繁杂的文件,是一个不可避免的话题。此时作为一种已经被实践证明过的思想模式一直得到大家的青睐,这就是控制反转(IOC)。
IOC定义
先看一下维基百科上的定义:
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
原则
- 高层模块不应该依赖低层模块。两个都应该依赖抽象
- 抽象不应该依赖具体实现
- 面向接口编程,而非面向实现编程
针对前端来说,接口的概念不那么清晰明了,不像强类型语言。
概念是比较枯燥的,下面结合例子来看一下可能更好理解一点。
目的
根据概念可以看到最主要的目的就是降低耦合,提高扩展性。在深究之前,我们先看下代码耦合
代码耦合
所谓耦合,可以如下图显示:
比较清晰明了,代码相互之间的联系太直接:
假如obj2报错,那么整个系统也都报错了。
所以我们的目的就是降低二者之间的耦合度,
结合图来说比较清晰,
如果两者不这么直接的发生关系,那么相互影响的概率就小了那么多了。
另外,这是比较少的模块,常规项目里显然不仅仅是只有这么少,想象一下多个模块的场景:
这里除了耦合之外,不同齿轮之间的依赖关系也是个头疼的问题,迭代个几个版本之后发现,这是什么东西,一动就有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的几条原则,我们进行下改进。
高层模块不应该依赖低层模块。两个都应该依赖抽象
这里player是高层模块,直接依赖了球队这个低级模块。所以我们将两者解耦,player不再直接依赖于该team这个class抽象不应该依赖具体实现,具体实现应该依赖抽象
具体到这里来看我们的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的编程思想,主要有两种实现方式:依赖注入和依赖查找。依赖查不太常用,常见的是依赖注入。
依赖注入
在js中常见的就是依赖注入。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中。
在RequireJS/AMD的模块加载器的实现就是基于依赖注入来的,还有大名鼎鼎的angular,其实现也使用了大量的依赖注入。
结束语
关于控制反转,一句话总结:控制反转这里控制权从使用者本身转移到第三方容器上,而非是转移到被调用者上,这里需要明确不要疑惑。控制反转是一种思想,依赖注入是一种设计模式。
可能听起来比较抽象,其实我们平时开发中见到和用到的也是蛮多的,可能原来没有对应起来罢了。
至于依赖注入,前端领域用到的就更多了,下面我将结合自身实践翻译一篇个人认为很好的文章Dependency-injection-in-JavaScript,来进一步深入依赖注入。
至此,个人见解分享完毕,抛砖引玉,希望共同学习进步。
前端解读控制反转(IOC)的更多相关文章
- 前端理解控制反转ioc
工作一直都是写前端,而且都是偏业务的.相关的框架代码层面的了解还是有很大的缺失.一直想多写些维护性,可读性强的代码. 这段时间对控制反转ioc,这样的设计有了一个初步的了解. 前端为弱语言,平时代码的 ...
- 20181123_控制反转(IOC)和依赖注入(DI)
一. 控制反转和依赖注入: 控制反转的前提, 是依赖倒置原则, 系统架构时,高层模块不应该依赖于低层模块,二者通过抽象来依赖 (依赖抽象,而不是细节) 如果要想做到控制反转(IOC), 就必须要使 ...
- Spring框架系列(3) - 深入浅出Spring核心之控制反转(IOC)
在Spring基础 - Spring简单例子引入Spring的核心中向你展示了IoC的基础含义,同时以此发散了一些IoC相关知识点; 本节将在此基础上进一步解读IOC的含义以及IOC的使用方式.@pd ...
- 控制反转IoC简介
控制反转IoC简介 在实际的应用开发中,我们需要尽量避免和降低对象间的依赖关系,即降低耦合度.通常的业务对象之间都是互相依赖的,业务对象与业务对象.业务对象与持久层.业务对象与各种资源之间都存在这样或 ...
- 浅析“依赖注入(DI)/控制反转(IOC)”的实现思路
开始学习Spring的时候,对依赖注入(DI)——也叫控制反转(IOC)—— 的理解不是很深刻.随着学习的深入,也逐渐有了自己的认识,在此记录,也希望能帮助其他入门同学更深入地理解Spring.本文不 ...
- 控制反转IOC的依赖注入方式
引言: 项目中遇到关于IOC的一些内容,因为和正常的逻辑代码比较起来,IOC有点反常.因此本文记录IOC的一些基础知识,并附有相应的简单实例,而在实际项目中再复杂的应用也只是在基本应用的基础上扩展而来 ...
- 控制反转IOC与依赖注入DI
理解 IOC http://www.cnblogs.com/zhangchenliang/archive/2013/01/08/2850970.html IOC 相关实例 的http:// ...
- 控制反转(Ioc)和依赖注入(DI)
控制反转IOC, 全称 “Inversion of Control”.依赖注入DI, 全称 “Dependency Injection”. 面向的问题:软件开发中,为了降低模块间.类间的耦合度,提倡基 ...
- 控制反转IOC与依赖注入DI【转】
转自:http://my.oschina.net/1pei/blog/492601 一直对控制反转.依赖注入不太明白,看到这篇文章感觉有点懂了,介绍的很详细. 1. IoC理论的背景我们都知道,在采用 ...
随机推荐
- mongodb系列~ mongodb慢语句(3)
简介: 关于mongodb慢日志是如何收集 一 mongodb慢日志的开启 1 直接设置参数,不重启服务:db.setProfilingLevel(1) 2 添加启动参数,重启服务:添加profile ...
- nginx 配置文件[转]
#运行用户 user nobody; #启动进程,通常设置成和cpu的数量相等 worker_processes 1; #全局错误日志及PID文件 #error_log logs/error.log; ...
- mysql 索引无法使用问题
今天碰到一个问题,表中有一个索引不使用,怎么强制也没用 ,force index都没用, 后来才发现是类型不对, 比如索引字段是int,如果参数使用varchar,那么是无法使用索引的,参数类型最好统 ...
- UML和模式应用4:初始阶段(5)--用例编写的准则
1.前言 本文主要介绍用例编写时所遵循的几条基本准则. 2.用例编写的准则 2.1 以本质的风格编写用例 如系统认证,而不要说 需要输入ID进行认证等 2.2 编写简洁的用例 如系统认证,不要说 这个 ...
- cocos2d-x在App中的应用
cocos2d-x是一个应用广泛的开源游戏引擎,主要是应用与开发2D游戏,开源运行于多个平台,如果只是针对于移动端平台而言,可以运行于android和ios平台. cocos2d-x目前的版本是3.1 ...
- Cookie/Session机制详解(转载)
原文链接:http://blog.csdn.net/fangaoxin/article/details/6952954 会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用 ...
- openwrt git 代码下载地址
openwrt 各个版本代码下载 trunk:git clone git://github.com/openwrt/openwrt.git 15.05 (Chaos Calmer)git clone ...
- gitlab代码仓库迁移
有的时候我们需要对gitlab上的代码进行迁移,希望在迁移后能保持原有的branch.tag.commit记录等.可以使用以下方式: 1.clone代码到本地. 2.修改remote仓库的地址,添加新 ...
- ANN算法总结
kd-tree kd-tree works poorly in high dimensions (k<30) 自己实验的时候差不多20到30左右吧,超过之后,就真的很慢了 faiss suppo ...
- 彻底理解this指向-----实例分析
this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁,一定要搞清楚这个. 情况1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是wind ...