您的位置:首页 > 其它

依赖注入浅析

2020-01-14 19:59 489 查看

一、名词解析。

维基百科上的解释是依赖注入(Dependency Injection,简称DI)是实现控制反转(Inversion of Control,缩写为IoC)的一种用以降低代码耦合度的一种设计模式。

二、进入主题。

请先看下面的示例有什么问题没有

@interface Service : NSObject
- (void)doSomeThing;
@end

@implementation Service
- (void)doSomeThing {
// TODO:
}
@end

@interface Client : NSObject {
Service *_service;
}
- (void)doTheWork;
@end

@implementation Client

- (instancetype)init {
self = [super init];
if (self) {
_service = [Service new];
}
return self;
}

- (void)doTheWork {
NSLog(@"I'm do the work, and ask service do some subwork");
[_service doSomeThing];
}

@end

咋一看,这样的代码看起来好像也没有什么问题:Client有一个Service成员,Client直接New一个Service成员,然后在工作时将一部分转包给Service去做。但是,在这种情况下,其实Client和Service就有一种hard-coded的依赖。

依赖注入,就是让Client不去显示的通过构造函数(objc's all & init or new)初始化成员变量的技术。

 

依赖注入有三种方式:

1. 构造函数注入:通过构造函数去提供所依赖的对象 (objc的init)

@implementation Client

- (instancetype)initWithService:(Service *)sevice {
self = [super init];
if (self) {
_service = sevice;
}
return self;
}

@end

 

2. setter注入

@implementation Client

- (void)setService:(Service *)service {
_service = service;
}

@end

  

3. 接口注入

@protocol ServiceProtocol <NSObject>

- (void)doSomeThing;

@end
@interface Service : NSObject <ServiceProtocol>
@end

@implementation Service
- (void)doSomeThing {
// TODO:
}
@end

@interface Client : NSObject {
id<ServiceProtocol> _service;
}
- (void)doTheWork;
@end

@implementation Client

- (void)setService:(id<ServiceProtocol>)service {
_service = service;
}

@end

  

我们可以看到,其实构造函数注入和setter注入也还是都依赖于具体的service类开。所以第三种接口注入其实才是比较好的方式。当然还应该加上一些对边界条件的检测。把三种注入方法接合起来。

@implementation Client

- (void)setService:(id<ServiceProtocol>)service {
_service = service;
}

- (instancetype)initWithService:(id<ServiceProtocol>)sevice {
self = [super init];
if (self) {
_service = sevice;
}
return self;
}

- (BOOL)validateState {
if (!_service) {
NSLog(@"Service cannot be nil");
// TODO: maybe throw a exception
return NO;
}
return YES;
}

- (BOOL)doTheWork {
BOOL done = NO;
if ([self validateState]) {
NSLog(@"I'm do the work, and ask service do some subwork");
[_service doSomeThing];
done = YES;
}
return done;
}

@end

  

有的人已经看不下去了:不就经常TM说的面向接口编程吗?yes, you are right.

还有人要说了,我们用第三方的库,用系统的库,有太多地方都是直接依赖的了,而且如果所有地方都要这样不直接依赖,那还不搞死人?

 

是的,面向对象也好,面向接口也好,都是有一个度的。做人做事何尝又不是呢。面向对象与面向过程不是互斥的。无论你怎么抽象、怎么面积对象,到具体的方法逻辑里面那一定是面向过程的。

一样的,通过setter注入也好,接口注入也好,最后真正决定要使用哪一个实现了service protocol的类型的时候,总得有一个地方去初始化吧?那么好了,在那个地方一定就是和这个具体的Service类型强依赖的。我们要做的只是把一些今后可能会变的地方,一些粒度大一些的模块这样实现便好。

 

关于依赖注入的库:Typhoon(objc, swift) Swinject 

 

Reference: https://en.wikipedia.org/wiki/Dependency_injection

转载于:https://www.cnblogs.com/csutanyu/p/4749974.html

  • 点赞
  • 收藏
  • 分享
  • 文章举报
dazheng6893 发布了0 篇原创文章 · 获赞 0 · 访问量 34 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: