Web前端开发|IoC是什么?_惠州前端培训学校
作者:alu发布时间:2022-03-18分类:前端开发专业浏览:659
IoC是什么?这是大家在学习前端的过程都会遇到的问题,那么下面我们一起来看看惠州北大青鸟学术部老师是怎么解答的。
Web前端技术越来越火,前端应用在不断壮大的过程中,内部模块间的依赖可能也会随之越来越复杂,模块间的 低复用性 导致应用 难以维护,不过我们可以借助计算机领域的一些优秀的编程理念来一定程度上解决这些问题,下面我们就来一起看一看IoC。
一、什么是IoC
IoC 的全称叫做 Inversion of Control,可翻译为为「控制反转」或「依赖倒置」,它主要包含了三个准则:
1、高层次的模块不应该依赖于低层次的模块,它们都应该依赖于抽象
2、抽象不应该依赖于具体实现,具体实现应该依赖于抽象
3、面向接口编程 而不要面向实现编程
概念总是抽象的,所以下面将以一个例子来解释上述的概念:
假设需要构建一款应用叫 App,它包含一个路由模块 Router 和一个页面监控模块 Track,一开始可能会这么实现:
// app.js
import Router from './modules/Router';
import Track from './modules/Track';
class App {
constructor(options) {
this.options = options;
this.router = new Router();
this.track = new Track();
this.init();
}
init() {
window.addEventListener('DOMContentLoaded', () => {
this.router.to('home');
this.track.tracking();
this.options.onReady();
});
}
}
// index.js
import App from 'path/to/App';
ew App({
onReady() {
// do something here...
},
});
嗯,看起来没什么问题,但是实际应用中需求是非常多变的,可能需要给路由新增功能(比如实现 history 模式)或者更新配置(启用 history, ew Router({ mode: 'history' }))。这就不得不在 App 内部去修改这两个模块,这是一个 INNER BREAKING 的操作,而对于之前测试通过了的 App 来说,也必须重新测试。
很明显,这不是一个好的应用结构,高层次的模块 App 依赖了两个低层次的模块 Router 和 Track,对低层次模块的修改都会影响高层次的模块 App。那么如何解决这个问题呢,解决方案就是接下来要讲述的 依赖注入(Dependency Injection)。
二、依赖注入
所谓的依赖注入,简单来说就是把高层模块所依赖的模块通过传参的方式把依赖「注入」到模块内部,上面的代码可以通过依赖注入的方式改造成如下方式:
// app.js
class App {
constructor(options) {
this.options = options;
this.router = options.router;
this.track = options.track;
this.init();
}
init() {
window.addEventListener('DOMContentLoaded', () => {
this.router.to('home');
this.track.tracking();
this.options.onReady();
});
}
}
// index.js
import App from 'path/to/App';
import Router from './modules/Router';
import Track from './modules/Track';
ew App({
router: new Router(),
track: new Track(),
onReady() {
// do something here...
},
});
可以看到,通过依赖注入解决了上面所说的 INNER BREAKING 的问题,可以直接在 App 外部对各个模块进行修改而不影响内部。
是不是就万事大吉了?理想很丰满,但现实却是很骨感的,没过两天产品就给你提了一个新需求,给 App 添加一个分享模块 Share。这样的话又回到了上面所提到的 INNER BREAKING 的问题上:你不得不对 App 模块进行修改加上一行 this.share = options.share,这明显不是我们所期望的。
虽然 App 通过依赖注入的方式在一定程度上解耦了与其他几个模块的依赖关系,但是还不够彻底,其中的 this.router 和 this.track 等属性其实都还是对「具体实现」的依赖,明显违背了 IoC 思想的准则,那如何进一步抽象 App 模块呢。
Talk is cheap, show you the code
class App {
static modules = []
constructor(options) {
this.options = options;
this.init();
}
init() {
window.addEventListener('DOMContentLoaded', () => {
this.initModules();
this.options.onReady(this);
});
}
static use(module) {
Array.isArray(module) ? module.map(item => App.use(item)) : App.modules.push(module);
}
initModules() {
App.modules.map(module => module.init && typeof module.init == 'function' && module.init(this));
}
}
经过改造后 App 内已经没有「具体实现」了,看不到任何业务代码了,那么如何使用 App 来管理我们的依赖呢:
// modules/Router.js
import Router from 'path/to/Router';
export default {
init(app) {
app.router = new Router(app.options.router);
app.router.to('home');
}
};
// modules/Track.js
import Track from 'path/to/Track';
export default {
init(app) {
app.track = new Track(app.options.track);
app.track.tracking();
}
};
// index.js
import App from 'path/to/App';
import Router from './modules/Router';
import Track from './modules/Track';
App.use([Router, Track]);
ew App({
router: {
mode: 'history',
},
track: {
// ...
},
onReady(app) {
// app.options ...
},
});
可以发现 App 模块在使用上也非常的方便,通过 App.use() 方法来「注入」依赖,在 ./modules/some-module.js 中按照一定的「约定」去初始化相关配置,比如此时需要新增一个 Share 模块的话,无需到 App 内部去修改内容:
// modules/Share.js
import Share from 'path/to/Share';
export default {
init(app) {
app.share = new Share();
app.setShare = data => app.share.setShare(data);
}
};
// index.js
App.use(Share);
ew App({
// ...
onReady(app) {
app.setShare({
title: 'Hello IoC.',
description: 'description here...',
// some other data here...
});
}
});
直接在 App 外部去 use 这个 Share 模块即可,对模块的注入和配置极为方便。
那么在 App 内部到底做了哪些工作呢,首先从 App.use 方法说起:
class App {
static modules = []
static use(module) {
Array.isArray(module) ? module.map(item => App.use(item)) : App.modules.push(module);
}
}
可以很清楚的发现,App.use 做了一件非常简单的事情,就是把依赖保存在了 App.modules 属性中,等待后续初始化模块的时候被调用。
接下来我们看一下模块初始化方法 this.initModules() 具体做了什么事情:
class App {
initModules() {
App.modules.map(module => module.init && typeof module.init == 'function' && module.init(this));
}
}
可以发现该方法同样做了一件非常简单的事情,就是遍历 App.modules 中所有的模块,判断模块是否包含 init 属性且该属性必须是一个函数,如果判断通过的话,该方法就会去执行模块的 init 方法并把 App 的实例 this 传入其中,以便在模块中引用它。
从这个方法中可以看出,要实现一个可以被 App.use() 的模块,就必须满足两个「约定」:
1. 模块必须包含 init 属性
2. init 必须是一个函数
这其实就是 IoC 思想中对「面向接口编程 而不要面向实现编程」这一准则的很好的体现。App 不关心模块具体实现了什么,只要满足对 接口 init 的「约定」就可以了。
此时回去看 Router 的模块的实现就可以很容易理解为什么要怎么写了:
// modules/Router.js
import Router from 'path/to/Router';
export default {
init(app) {
app.router = new Router(app.options.router);
app.router.to('home');
}
};
最后总结:
App 模块此时应该称之为「容器」比较合适了,跟业务已经没有任何关系了,它仅仅只是提供了一些方法来辅助管理注入的依赖和控制模块如何执行。
控制反转(Inversion of Control)是一种「思想」,依赖注入(Dependency Injection)则是这一思想的一种具体「实现方式」,而这里的 App 则是辅助依赖管理的一个「容器」。
想学前端,联系在线客服,或者可以来惠州北大青鸟新方舟校区详细了解。
标签:惠州前端培训学校惠州前端基础惠州前端培训北大青鸟IT计算机学校北大青鸟IT软件学校前端北大青鸟IT学校惠州北大青鸟北大青鸟
- 前端开发专业排行
- 标签列表
-
- Java (3694)
- 北大青鸟 (3713)
- 软件开发 (3613)
- JAVA (3413)
- UI设计入门 (2093)
- 惠州北大青鸟 (4375)
- 惠州IT培训 (2558)
- UI设计培训 (2090)
- 惠州UI设计培训 (2095)
- 惠州UI设计培训学校 (2090)
- 惠州计算机软件培训 (6260)
- 惠州计算件软件开发 (6260)
- 惠州计算机软件基础 (6261)
- 惠州计算机JAVA培训 (3574)
- 惠州计算机Java软件开发 (3620)
- 惠州计算机JAVA软件开发 (4645)
- 惠州计算机JAVA软件开发学校 (3338)
- 惠州计算机Java软件开发培训 (3338)
- 北大青鸟IT计算机学校 (5048)
- 北大青鸟IT软件学校 (5062)
- 北大青鸟IT学校 (5059)
- 惠州计算机UI设计软件开发 (2088)
- UI设计基础教程 (2088)
- UI设计是什么 (2088)
- UI设计教程 (2088)
- 网站分类
-
- 计算机教程
- 计算机入门
- 职业学校
- 新闻动态
- 专业课程
- 热门技术
- SEO
- 培训教程
- windows
- linux教程
- 系统集成
- 网站开发
- Html5
- 办公软件
- 师资力量
- 热点问答
- 联系我们
- 计算机学校
- 惠州计算机学校
- 河源计算机学校
- 广州计算机学校
- 深圳计算机学校
- 湛江计算机学校
- 佛山计算机学校
- IT计算机培训信息
- 设计专业
- UI
- 影视特效
- 游戏动漫设计
- Photoshop
- AI设计
- 软件教程
- Java技术
- C语言/C++语言培训
- C#
- Python技术
- PHP
- 数据库
- SQL Server
- 网络教程
- 网络安全
- 网络营销
- 软件专业
- 大数据专业
- 前端开发专业
- 软件测试专业
- Python专业
- 软件实施
- 珠海计算机学校
- 初中生学什么好
- 计算机认证
- 文章归档
-
- 2024年12月 (15)
- 2024年11月 (45)
- 2024年10月 (32)
- 2024年9月 (29)
- 2024年8月 (68)
- 2024年7月 (59)
- 2024年6月 (43)
- 2024年5月 (48)
- 2024年4月 (80)
- 2024年3月 (65)
- 2024年2月 (54)
- 2024年1月 (25)
- 2023年12月 (12)
- 2023年11月 (73)
- 2023年10月 (134)
- 2023年9月 (34)
- 2023年8月 (3)
- 2023年7月 (3)
- 2023年6月 (12)
- 2023年5月 (30)
- 2023年4月 (72)
- 2023年3月 (11)
- 2023年2月 (34)
- 2023年1月 (37)
- 2022年12月 (78)
- 2022年11月 (359)
- 2022年6月 (1193)
- 2022年5月 (570)
- 2022年4月 (1567)
- 2022年3月 (982)
- 2022年2月 (54)
- 2022年1月 (182)
- 2021年9月 (308)
- 2021年8月 (1704)
- 2021年7月 (2423)
- 2021年6月 (1806)
- 2021年5月 (1569)
- 2021年4月 (1380)
- 2021年3月 (1255)
- 2021年2月 (709)
- 2021年1月 (1521)
- 2020年12月 (3626)
- 2020年11月 (1646)
- 2020年10月 (1046)
- 2020年9月 (592)
- 最近发表
-
- 东莞信息:2024年长安镇技能创业咖啡节成功举办|||广州计算机软件培训
- 河源信息:本周六百企万岗职等你来市县镇联动大型招聘活动即将开幕!|||计算机培训学校招生
- 茂名信息:茂名组织劳动人事仲裁案件庭审观摩活动|||大学生计算机培训学校
- 茂名信息:茂名市人力资源和社会保障局相继开展诚信宣传四进主题实践活动|||广州市北大青鸟计算机职业培训学校
- 茂名信息:凝心聚力共筑平安茂名市人力资源和社会保障局开展平安建设暨一感两度宣传活动|||大学生计算机培训学校
- 汕头信息:汕头市人力资源和社会保障局开展宪法宣传周活动|||北大青鸟计算机培训中心
- 梅州信息:梅州市人社局开展2024年第四季度诚信文化主题宣传志愿服务活动|||电脑计算机编程培训学校
- 东莞信息:塘厦人社分局联合消防大队开展技工学校等机构消防安全培训|||广州计算机软件培训
- 东莞信息:塘厦塘厦镇成功举办优才服务区第二期业务提升培训班|||计算机软件培训学校
- 东莞信息:2024年横沥镇举办模具设计师职业技能大赛|||广州计算机软件培训