2026-10-21 21:23:46
依赖注入(Dependency Injection, DI)是一种设计模式,通过将类的依赖项从外部传入,实现控制反转(Inversion of Control, IoC),从而降低代码耦合度,提升可测试性和可维护性。其核心思想是将对象的创建与使用分离,由外部统一管理依赖关系。
一、依赖注入的核心概念控制反转(IoC)
传统方式:客户类直接控制依赖对象的创建和调用(如Car类内部直接实例化Tyre)。
IoC方式:将控制权交给外部框架或容器(如网络请求的completionHandler由网络库调用,而非业务方主动触发)。
优势:解耦控制逻辑与业务逻辑,提升模块化程度。
依赖注入的实现
外部创建依赖:依赖对象在类外部初始化,通过构造器、属性或方法注入到类中。
示例对比:
耦合代码:
class Car { var tyres: [Tyre] init() { tyres = [Tyre(), Tyre(), Tyre(), Tyre()] } // 轮胎创建逻辑与Car绑定}解耦代码:
class Car { var tyres: [Tyre] init(tyres: [Tyre]) { self.tyres = tyres } // 依赖通过构造器注入}构造器注入(Initializer Injection)
适用场景:依赖对象生命周期与宿主类相同。
示例:
class DataViewModel { let networking: Networking init(networking: Networking) { self.networking = networking }}属性注入(Property Injection)
适用场景:无法通过构造器注入时(如Storyboard初始化的ViewController)。
示例:
class ClientObject { var dependency: DependencyObject? // 通过公开属性注入}方法注入(Method Injection)
适用场景:依赖需延迟创建或按条件注入。
示例:
protocol DependencyProvider { func provideDependency() -> DependencyObject}作用
统一管理依赖的创建、生命周期和注入,避免重复代码。
支持动态替换依赖实现(如测试时注入Mock对象)。
核心功能
注册(Register):绑定接口与实现类。
container.register(type: Networking.self, component: DefaultNetworking())解析(Resolve):根据类型获取依赖实例。
let networking = container.resolve(Networking.self)生命周期管理:自动处置单例或临时对象。
简单实现示例
protocol DIContainer { func register<T>(type: T.Type, component: Any) func resolve<T>(type: T.Type) -> T?}class DefaultDIContainer: DIContainer { private var components = [String: Any]() func register<T>(type: T.Type, component: Any) { components["(type)"] = component } func resolve<T>(type: T.Type) -> T? { return components["(type)"] as? T }}依赖注入通过将控制权反转给外部容器,实现了高内聚低耦合的代码结构。无论是小型项目的手动注入,还是大型框架的容器管理,其核心目标都是提升代码的灵活性和可测试性。掌握这一模式可显著提高代码质量,尤其在需要频繁替换依赖或编写单元测试的场景中。