设计模式之——依赖反转
✨文章摘要(AI生成)
本文介绍了面向对象设计中的依赖反转原则(Dependency Inversion)。文章首先解释了依赖反转的核心概念:高层模块应该依赖于抽象接口而非具体实现。随后通过 TypeScript 中的实际例子,展示了如何使用接口和依赖注入来实现依赖反转,以 useStorage
方法为例说明了如何通过抽象接口实现代码的解耦和扩展。最后总结了依赖反转带来的好处,包括代码解耦、可扩展性和可测试性的提升。
依赖反转(Dependency Inversion)是面向对象设计中的一种设计原则,它强调高层模块不应该依赖于低层模块的具体实现,而是应该依赖于抽象接口或协议。这个原则是由罗伯特·C·马丁(Robert C. Martin)提出的,也是SOLID原则中的其中一个。
原理
- 高层模块应该依赖于抽象接口或协议,而不是具体实现。
- 抽象接口或协议应该由低层模块来实现。
具体来说,依赖反转可以通过以下方式实现:
- 定义抽象接口或协议,描述高层模块所需的功能。
- 高层模块通过依赖注入(Dependency Injection)或者工厂模式等方式,将具体实现的依赖关系传递给低层模块。
- 低层模块实现抽象接口或协议,并提供具体的功能实现。
- 高层模块通过抽象接口或协议来使用低层模块的功能,而不需要关心具体实现。
例子
将函数的内部易变的逻辑抽象为参数,带来更好的可维护性,这里先以vue use
中的 useStroage
方法为例
ts
// 定义通用接口
export interface StorageLike {
getItem(key: string): string | null
setItem(key: string, value: string): void
removeItem(key: string): void
}
// 定义函数签名
// 函数签名中storage参数为外部传入,可以是SessionStorage也可以是LocalStroage可以是自定义的对StorageLike接口的实现
function useStorage(key: string, storage?: StorageLike): RemovableRef<string>
// 使用示例
const id = useStorage('my-id', sessionStorage) ;
const id = useStorage('my-id', localStorage)
// 自定义stroage,比如对indexdb的封装,只要实现了StorageLike接口就可以复用useStorage中通用的逻辑
class CustomStorage implements StorageLike {
getItem(key) {...}
setItem(key, value){....}
removeItem(key: string) {...}
}
const customStorage = new CustomStorage()
const id = useStorage('my-id', customStorage)
总结
- 解耦:高层模块和低层模块之间的依赖关系被解耦,使得代码更加灵活和可维护。
- 可扩展性:通过替换具体实现,可以轻松地扩展系统的功能。
- 可测试性:依赖反转使得高层模块的测试更加容易,可以使用模拟对象或者桩对象来替代具体实现。