适配器模式
意图:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器模式有两种实现方式:类适配器和对象适配器。
类适配器模式.jpg 对象适配器模式.jpg角色和职责
- Client
与符合Target接口的对象协同。 - Adapter
对Adaptee的接口与Target进行适配 - Target
定义Client使用的与特定领域相关的接口。 - Adaptee
定义一个已经存在的接口,这个接口需要适配
代码示例
类适配器
#import <Foundation/Foundation.h>
//被适配的类
@interface Adaptee : NSObject
@end
@implementation Adaptee
//输出220V电压
- (NSInteger)output220V {
NSInteger src = 220;
NSLog(@"电压%ld伏", src);
return src;
}
@end
//适配接口
@protocol ITarget <NSObject>
- (NSInteger)output5V;
@end
//适配器类
@interface Adapter : Adaptee <ITarget>
@end
@implementation Adapter
- (NSInteger)output5V {
NSInteger srcV = [self output220V];
NSInteger dstV = srcV / 44;
return dstV;
}
@end
@interface Phone : NSObject
@end
@implementation Phone
//充电方法
- (void)charging:(id<ITarget>)iTarget {
if ([iTarget output5V] == 5) {
NSLog(@"电压为5V,可以充电");
}else {
NSLog(@"电压大于5V,不能充电");
}
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"类适配器");
Phone *phone = [[Phone alloc] init];
[phone charging:[[Adapter alloc] init]];
}
return 0;
}
/*
类适配器
电压220伏
电压为5V,可以充电
*/
对象适配器
#import <Foundation/Foundation.h>
//被适配的类
@interface Adaptee : NSObject
@end
@implementation Adaptee
//输出220V电压
- (NSInteger)output220V {
NSInteger src = 220;
NSLog(@"电压%ld伏", src);
return src;
}
@end
//适配接口
@protocol ITarget <NSObject>
- (NSInteger)output5V;
@end
//适配器类
@interface Adapter : NSObject <ITarget>
@property (nonatomic, strong) Adaptee *adaptee;
@end
@implementation Adapter
//初始化方法创建adaptee或者setter方法都可以(聚合)
- (instancetype)init {
if (self = [super init]) {
self.adaptee = [[Adaptee alloc] init];
}
return self;
}
- (NSInteger)output5V {
NSInteger srcV = [self.adaptee output220V];
NSInteger dstV = srcV / 44;
return dstV;
}
@end
@interface Phone : NSObject
@end
@implementation Phone
//充电方法
- (void)charging:(id<ITarget>)iTarget {
if ([iTarget output5V] == 5) {
NSLog(@"电压为5V,可以充电");
}else {
NSLog(@"电压大于5V,不能充电");
}
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"对象适配器");
Phone *phone = [[Phone alloc] init];
[phone charging:[[Adapter alloc] init]];
}
return 0;
}
/*
对象适配器
电压220伏
电压为5V,可以充电
*/
针对这两种实现方式,在实际开发中,选择使用哪一种呢?判断的标准主要有两个,一个是Adaptee接口的个数,另一个是Adaptee和Target的契合程度。
- 如果Adaptee接口不多,两种方式都可以。
- 如果Adaptee接口多,Adaptee和Target接口大部分相同,那么推荐类适配器,因为Adaptor复用父类Adaptee的接口,比对象适配器的组合方式,Adaptor的代码量少一些。
- 如果Adaptee接口多,Adaptee和Target接口大部分不相同,那么推荐对象适配器,因为组合结构相对于继承更灵活。
用处
一般来说,适配器模式是一种“补偿模式”,用来补救设计上的缺陷。如果设计就协调好规避接口掉接口不兼容的问题,那么这种模式就没有应用的机会了。
- 封装有缺陷的接口设计
- 统一多个类的接口设计
- 替换依赖的外部系统
- 兼容老版本接口
- 适配不同格式的数据
iOS中可以这么理解:一个现有类需要适应变化的问题。
Model映射成ViewModel
角色和职责
- 适配器
VM - 成员变量
持有引用属性 - 被适配对象
Model
优点
类适配器
- 由于其继承了Adaptee类,所以它可以根据需求重写Adaptee类的方法,使得Adapter的灵活性增强了,提高了类的复用。
对象适配器
- 根据“合成复用原则”,使用组合替代继承,解决了类适配器必须继承Adaptee的局限性。
- 使用成本更低,更灵活
缺点
类适配器
- 由于OC不支持
多继承
,所以至多只能适配一个适配者类,类适配器一方须是协议,有一定局限性。 - Adaptee类的方法在Adapter中都会暴露出来,增加了使用成本(如果方法多的话)。
对象适配器
- 过多地使用适配器,会让系统非常混乱,明明看到调用的是 A 接口,其实内部被适配成了 B 接口。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
网友评论