DI和IOC

依赖注入(Dependency Injection, DI)和控制反转(Inversion of Control, IoC)是面向对象编程中的两个重要概念,它们紧密相关并在现代软件开发中经常结合使用。

依赖注入: 依赖注入是一种设计模式,它旨在解决类之间的耦合问题。在传统的编程方式中,一个类如果需要使用另一个类的服务(即有依赖关系),通常会自己去创建或查找这个依赖对象。而在依赖注入的模式下,创建和管理依赖关系的责任从被依赖的对象转移到了外部容器或者客户端代码中。具体来说,不是对象自己创建或查找依赖,而是通过构造函数、属性或方法将依赖传递给它。这样做的好处包括提高代码的可测试性、可复用性和松耦合度。

控制反转: 控制反转是一个更抽象的概念,它描述了一种程序设计原则,在这种原则下,对象不再负责自身的生命周期管理和依赖获取,而把这些控制权“反转”交给了一个第三方框架或容器来处理。IoC 容器负责创建对象,管理它们的生命周期,并在适当的时候自动将依赖注入到各个对象中。

两者的关系: 依赖注入是实现控制反转的一种常见手段或者说具体实践形式。也就是说,当我们在谈论控制反转时,我们关注的是设计理念层面,即如何把对象的控制权转移出去;而依赖注入则是这一理念在实际编程中的体现,它是控制反转的具体实现途径之一,通过注入依赖对象的方式达到解耦的目的。

总结起来,IoC 是一种高层次的设计思想,强调的是对象之间责任的归属变化;DI 则是 IoC 的一种具体应用,通过依赖注入机制实现了控制权的反转,降低了组件间的耦合度,提高了系统的灵活性和可维护性。

在Node.js环境中,我们可以使用一个简单的工厂函数或者依赖注入容器(DI Container)来实现依赖注入和控制反转的概念。以下是一个Node.js应用中依赖注入和控制反转的简单示例:

// 定义一个日志服务接口与其实现
interface Logger {log(message: string): void;
}class ConsoleLogger implements Logger {log(message: string) {console.log(`Logging to console: ${message}`);}
}// 假设这是我们的业务逻辑类,在没有依赖注入时它会自行创建并管理日志器
class BusinessServiceWithoutDI {private logger: Logger;constructor() {// 在这里直接创建了依赖对象this.logger = new ConsoleLogger();}doSomeBusinessLogic() {this.logger.log('Doing some business logic');}
}// 使用依赖注入后,业务逻辑类不再直接创建日志器实例
class BusinessServiceWithDI {private logger: Logger;// 构造函数注入constructor(logger: Logger) {// 日志器由外部传入this.logger = logger;}doSomeBusinessLogic() {this.logger.log('Doing some business logic with DI');}
}// 创建一个简易的IoC容器模拟
class DependencyContainer {createBusinessService(): BusinessServiceWithDI {const logger = new ConsoleLogger();// 容器负责创建并注入依赖return new BusinessServiceWithDI(logger);}
}// 使用IoC容器获取业务服务,并执行逻辑
const container = new DependencyContainer();
const service = container.createBusinessService();
service.doSomeBusinessLogic();

在这个Node.js示例中:

  • BusinessServiceWithoutDI 类展示了不使用依赖注入的情况,其中日志器是硬编码到业务类内部的。
  • BusinessServiceWithDI 类通过构造函数接受 Logger 实例作为参数,实现了依赖注入。
  • DependencyContainer 类作为一个简单的IoC容器实现,它负责创建依赖(例如 ConsoleLogger)并将其注入到业务服务中,从而实现了控制反转。

通过这样的方式,我们可以灵活地更换不同的日志实现,只需要在容器中更改创建的日志器实例即可,而无需修改业务逻辑类本身,增强了代码的可测试性和模块间的解耦。在实际大型项目中,可能还会使用更复杂的IoC容器库来管理服务和依赖关系。

在Node.js中,装饰器(Decorator)是一种特殊类型的声明,它可以被附加到类声明、方法、访问器、属性或参数上。结合装饰器和依赖注入(DI)的概念,我们可以创建一个更加简洁、直观的方式来管理对象的依赖关系,并实现控制反转(IoC)。以下是一个使用TypeScript和装饰器实现依赖注入的简化示例:

// 假设我们有一个日志服务接口及其实现
interface Logger {log(message: string): void;
}class ConsoleLogger implements Logger {log(message: string) {console.log(`Logging to console: ${message}`);}
}// 装饰器工厂函数来注入依赖
function Injectable(target: any, key: string, descriptor: PropertyDescriptor) {// 在这里可以模拟从容器获取依赖const logger = new ConsoleLogger();// 将依赖注入到目标对象的属性上target[key] = logger;return descriptor;
}// 使用装饰器的业务逻辑类
class BusinessService {@Injectableprivate logger!: Logger; // TypeScript中的可选断言表示此属性将在运行时被装饰器填充doSomeBusinessLogic() {this.logger.log('Doing some business logic with DI');}
}// 创建业务服务实例并执行逻辑
const service = new BusinessService();
service.doSomeBusinessLogic();

上述代码虽然展示了装饰器如何用于注入依赖,但它并不完全实现了完整的IoC容器的功能。在实际应用中,装饰器通常会配合元数据和反射API(如reflect-metadata库),以及一个真正的IoC容器来完成更复杂的依赖注入过程。

例如,如果要模拟一个更接近于真实IoC容器的行为,装饰器可能会用来标记哪些属性需要从容器中注入,然后在容器解析阶段通过反射API收集这些信息并自动注入依赖:

import 'reflect-metadata';// 定义注入元数据键
const InjectableMetadataKey = Symbol('injectable');// 装饰器用于标记需要注入的依赖类型
function Injectable(target: any, propertyKey: string | symbol) {Reflect.defineMetadata(InjectableMetadataKey, true, target, propertyKey);
}// IoC容器模拟(简化版)
class Container {private registry: Map<any, any> = new Map();register<T>(service: new (...args: any[]) => T, instance: T) {this.registry.set(service, instance);}resolve<T>(target: new (...args: any[]) => T): T {const targetPrototype = target.prototype;const propertiesToInject = Reflect.getOwnMetadata(InjectableMetadataKey, targetPrototype) || [];const instance = new target();for (const prop of propertiesToInject) {if (this.registry.has(prop)) {(instance as any)[prop] = this.registry.get(prop);} else {throw new Error(`No registered service found for ${prop.toString()}`);}}return instance;}
}// 注册服务到容器
const container = new Container();
container.register(Logger, new ConsoleLogger());// 业务逻辑类
@Reflect.metadata(InjectableMetadataKey, ['logger'])
class BetterBusinessService {constructor(private logger: Logger) {}doSomeBusinessLogic() {this.logger.log('Doing some business logic with DI from a container');}
}// 从IoC容器中获取并执行业务逻辑
const betterService = container.resolve(BetterBusinessService);
betterService.doSomeBusinessLogic();

在这个改进后的示例中,装饰器 @Injectable 标记了需要注入的属性,并且 Container 类负责解析这些依赖并在创建业务类实例时进行注入。这样就更好地体现了IoC容器的角色和依赖注入的机制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/644588.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024年可能会用到的几个地图可视化模板

前言 在数字化的过程中&#xff0c;数据可视化变得越来越重要。用户喜欢通过酷炫的视觉效果和直观的数据展示来理解数据。可视化地图组件是数据可视化的重要组成部分。这些地图组件提供多样化的效果&#xff0c;能够更好地展示数据的关系和地理分布&#xff0c;直观地将数据与…

高高兴兴过春节

一年一度的春节到了&#xff0c;到处洋溢着节日的气氛&#xff0c;到处彩灯高照&#xff0c;鞭炮齐鸣。   早上&#xff0c;我早早地起来和姐姐一起给爷爷奶奶拜年&#xff0c;爷爷很开心给了我一个大大的红包。吃完早饭&#xff0c;妈妈贴春联&#xff0c;爸爸挂灯笼&#x…

裁员潮中的自我成长,小故事,大鼓励

程序员裁员潮&#xff1a;技术变革下的职业危机 科技浪潮滚滚而来&#xff0c;我们了解科技&#xff0c;敬畏科技&#xff0c;拥抱科技。我们怕的不是裁员&#xff0c;而是自己无所适从的样子。 2023年&#xff0c;科技公司裁员的新闻屡见不鲜。据统计&#xff0c;今年以来&…

uniapp设置隐藏原生导航栏(3)

1、单个页面隐藏 在pages.json里配置 (第一种方式) {"path": "pages/home/index","style": {"navigationBarTitleText": "首页","navigationStyle": "custom" // 使用自定义导航栏&#xff0c;系统会关…

SpringBoot3+JDK21集成MyBatisPlus3.5.5

哈喽&#xff0c;大家好&#xff0c;我是呼噜噜&#xff0c;在上一篇文章SpringBoot3Jdk17来了 | 春见知识分享基础上&#xff0c;笔者把jdk17直接换成了jdk21一步到位&#xff0c;来踩踩坑 添加依赖 修改pom.xml文件&#xff1a; <dependency><groupId>com.baom…

日历的实现(java语言,包括钟表盘的实现、日历内部的日程提醒)

整理文件发现了大一的时候的作业&#xff0c;先感慨一波时间过得真的快&#xff01; 手中的这个是一个独立的java文件&#xff0c;可以直接就可以运行&#xff0c;应该是没有什么问题的。不想这个代码就此落灰了&#xff0c;希望可以给友友们带来一点点帮助&#xff01; 运行…

避免邮件进入垃圾箱的实用技巧:提高邮件接收率的策略

邮件进垃圾邮箱一部分原因是IP地址出现了问题&#xff0c;一部分是邮件内容。那我们应该怎么避免邮件进入垃圾邮箱呢&#xff1f; 1、邮件内容 1&#xff09;邮件标题 邮件标题是影响邮件打开率非常重要的因素&#xff0c;所以大家可能会在标题上放置一些吸引人的符号或者词…

聚道云连接器助力钉钉与金蝶云星辰无缝对接,实现多维度数据同步

客户介绍 某企业服务有限公司专注于为企业提供全方位、高质量的企业服务&#xff0c;致力于于企业管理咨询、企业形象策划、市场营销策划、财务管理咨询等方面。该公司拥有一支经验丰富、专业化的团队&#xff0c;他们深入了解企业需求&#xff0c;为客户提供个性化的解决方案…

美化环境,保护母亲河

同学们&#xff0c;你们好&#xff1a;       大家都应该知道吧&#xff0c;我们的母亲河——黄河正在慢慢地恶化。       知道吗&#xff1f;我国为了防止北京再次遭受沙尘暴的袭击&#xff0c;在新疆&#xff0c;宁夏等多个沙漠化地区都种上了一“层”绿色的“防沙…

列表的创建与删除

Python 中列表可以动态地添加、修改和删除元素&#xff0c;是 Python 编程中不可或缺的一部分。本文将介绍如何使用 Python 创建和删除列表&#xff0c;以及常用的方法和技巧。 创建列表 在 Python 中&#xff0c;我们可以使用一对方括号 [ ] 来创建一个空列表&#xff0c;也可…

关于 Go 协同程序(Coroutines 协程)、Go 汇编及一些注意事项。

参考&#xff1a; Go 汇编函数 - Go 语言高级编程 Go 嵌套汇编 - 掘金 (juejin.cn) 前言&#xff1a; Golang 适用 Go-Runtime&#xff08;Go 运行时&#xff0c;嵌入在被编译的PE可执行文件之中&#xff09;来管理调度协同程式的运行。 Go 语言没有多线程&#xff08;MT&a…

前端常见安全问题以及解决方案汇总

当涉及到前端开发时&#xff0c;安全性是至关重要的一环。在当今数字化的世界中&#xff0c;用户数据的保护和应用程序的安全性变得愈发重要。作为前端开发者&#xff0c;我们不仅需要关注页面的美观和功能&#xff0c;还要时刻牢记确保用户数据的安全以及应用程序的健壮性。本…

开源免费无广告Gopeed,现代化的高速下载器,支持(HTTP、BitTorrent、Magnet)等多种协议下载,开源免费、无广告、高度可定制、不限速。

目录 特点 支持的平台 一键部署 体验 特点 全平台支持、开源免费&#xff0c;不限速、无广告 遵循 GPL-3.0 开源协议 支持&#xff08;HTTP、BitTorrent、Magnet&#xff09;协议下载 高速下载&#xff0c;底层使用golang协程并发下载 每日自动更新 tracker 列表 去中心…

IPv4 over IPv6简介

在IPv4 Internet向IPv6 Internet过渡的后期&#xff0c;IPv6网络已被大量部署&#xff0c;此时可能出现IPv4孤岛。利用隧道技术可在IPv6网络上创建隧道&#xff0c;从而实现IPv4孤岛的互连。这类似于在IP网络上利用隧道技术部署VPN。在IPv6网络上用于连接IPv4孤岛的隧道&#x…

Oracle触发器简单应用示例

目录 一、应用描述 【1】、应用场景&#xff1a; 【2】、具体场景&#xff1a; 二、表结构介绍 【1】表名介绍&#xff1a; 【2】表结构&#xff1a; 三、设置触发器 一、应用描述 【1】、应用场景&#xff1a; 现有一张库存明细以及销售明细表&#xff0c;销售明细表发生…

知识图谱符号表示比较:特性图、RDF和OWL

目录 前言1 特性图&#xff1a;灵活的图结构表示1.1 优势与灵活性1.2 存储优化与查询优势1.3 挑战&#xff1a;缺乏工业标准支持 2 RDF&#xff08;Resource Description Framework&#xff09;&#xff1a;面向Web的数据标准2.1 三元组结构的优势2.2 语义标准与词汇丰富性2.3 …

Java算法 leetcode简单刷题记录6

Java算法 leetcode简单刷题记录6 环和杆&#xff1a; https://leetcode.cn/problems/rings-and-rods/ 统计范围内的元音字符串数&#xff1a; https://leetcode.cn/problems/count-the-number-of-vowel-strings-in-range/ 最长平衡子字符串&#xff1a; https://leetcode.cn/…

Golang学习之路一八类型别名和转换

Golang学习之路一八类型别名和转换 类型别名 使用 type 关键字自定义类型 package mainimport ("fmt""reflect" )// type 自定义类型名 原类型 type myint intfunc main() {var v1 myintv1 10fmt.Println(reflect.TypeOf(v1)) }// 输出结果: main.myin…

elment-plus如何引入scss文件实现自定义主题色

elment-plus如何引入scss文件实现自定义主题色&#xff01;如果您想修改elementPlus的默认主题色调&#xff0c;使用自定义的色调&#xff0c;可以考虑使用官方提供的解决办法。 第一步你需要在项目内安装sass插件包。 npm i sass -D 如图&#xff0c;安装完成后&#xff0c;你…

gdzwfw某省公共资源交易平台逆向学习

声明&#xff1a;本文中网站仅为学习技术使用&#xff0c;请勿暴力爬取数据。 学习地址&#xff1a;aHR0cHM6Ly95Z3AuZ2R6d2Z3Lmdvdi5jbi8jLzQ0L2p5Z2c 此网站采用请求头反爬&#xff0c;难点是请求头中几个参数是如何生成的&#xff08;别问为什么知道是请求头&#xff0c;一…