适配器模式
适配器模式的原理与实现
适配器模式的英文是"Adapter Design Pattern"。这个模式就是用来做适配的,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。
适配器模式有两种实现方式:类适配器和对象适配器。其中,类适配器使用继承关系来实现,对象适配器使用组合关系来实现。具体的代码示例如下。其中DMTarget表示要转化成的接口定义。DMAdaptee是一组不兼容DMTarget接口定义的接口,DMAdaptor 将DMAdaptee转化成一组符合DMTarget接口定义的接口。
@protocol DMTarget <NSObject>
- (void)f1;
- (void)f2;
- (void)fc;
@end
@interface DMAdaptee : NSObject
- (void)fa;
- (void)fb;
- (void)fc;
@end
@implementation DMAdaptee
- (void)fa
{
}
- (void)fb
{
}
- (void)fc
{
}
@end
// 基于继承模式实现 适配器模式
@interface DMAdaptor : DMAdaptee <DMTarget>
@end
@implementation DMAdaptor
- (void)f1
{
[self fa];
}
- (void)f2
{
// 自己实现
}
// 这里fc 函数不用实现,直接继承自Adaptee,这是跟对象适配器最大的不同点
@end
@protocol DMTarget <NSObject>
- (void)f1;
- (void)f2;
- (void)fc;
@end
@interface DMAdaptee : NSObject
- (void)fa;
- (void)fb;
- (void)fc;
@end
@implementation DMAdaptee
- (void)fa
{
}
- (void)fb
{
}
- (void)fc
{
}
@end
// 对象适配器
@interface DMAdaptor : NSObject <DMTarget>
- (instancetype)initWithAdaptee:(DMAdaptee *)adaptee;
@end
@interface DMAdaptor ()
@property (nonatomic, strong) DMAdaptee *adaptee;
@end
@implementation DMAdaptor
- (instancetype)initWithAdaptee:(DMAdaptee *)adaptee
{
if (self = [super init]) {
self.adaptee = adaptee;
}
return self;
}
- (void)f1
{
[self.adaptee fa];
}
- (void)f2
{
// 自己实现
}
- (void)fc
{
[self.adaptee fc];
}
@end
针对这两种实现方式,在实际的开发中,到底该如何选择使用那一种呢?判断的标准主要有两个,一个是DMAdaptee接口的个数,另一个是DMAdaptee 和DMTarget的契合程度。
- 如果DMAdaptee接口并不多,那两种实现方式都可以。
- 如果DMAdaptee接口很多,而且DMAdaptee和DMTarget 接口定义大部分都相同,那推荐使用类适配器,因为DMAdaptor复用父类DMAdaptee的接口,比起对象适配器的实现方式,DMAdaptor的代码量要少一些。
- 如果DMAdaptee接口很多,而且DMAdaptee和DMTarget 接口定义大部分都不相同,那推荐使用对象适配器,因为组合结构相对于继承更加灵活。
适配器模式应用场景总结
- 封装有缺陷的接口设计
假设依赖的外部系统在接口设计方面有缺陷(比如包含大量静态方法),引入之后会影响到自身代码的可测试性。为了隔离设计上的缺陷,希望对外部系统提供的接口进行二次封装,抽象出更好的接口设计,这个时候就可以使用适配器模式了。
// 这个类来自外部系统,无权对其进行修改
@interface DMCD : NSObject
+ (void)staticFunction1;
- (void)uglyNamingFunction2;
- (void)tooManyParamsFunction3ParamOne:(NSString *)paramOne paramTwo:(NSString *)paramTwo paramThree:(NSString *)paramThree;
- (void)lowPerformanceFunction4;
@end
@implementation DMCD
+ (void)staticFunction1
{
}
- (void)uglyNamingFunction2
{
}
- (void)tooManyParamsFunction3ParamOne:(NSString *)paramOne paramTwo:(NSString *)paramTwo paramThree:(NSString *)paramThree
{
}
- (void)lowPerformanceFunction4
{
}
@end
// 使用适配器模式进行重构
@interface DMParamsWrapper :NSObject
@property (nonatomic, strong) NSString *paramOne;
@property (nonatomic, strong) NSString *paramTwo;
@property (nonatomic, strong) NSString *paramThree;
@end
// 使用适配器模式进行重构
@protocol DMCDTarget <NSObject>
- (void)function1;
- (void)function2;
- (void)function3:(DMParamsWrapper *)paramsWrapper;
- (void)function4;
@end
// 使用适配器模式进行重构
@interface DMCDAdaptor : NSObject <DMCDTarget>
- (instancetype)initWithCD:(DMCD *)oneCD;
@end
@interface DMCDAdaptor ()
@property (nonatomic, strong) DMCD *oneCD;
@end
@implementation DMCDAdaptor
- (instancetype)initWithCD:(DMCD *)oneCD
{
if (self = [super init]) {
self.oneCD = oneCD;
}
return self;
}
#pragma mark - DMCDTarget 方法
- (void)function1
{
[DMCD staticFunction1];
}
- (void)function2
{
[self.oneCD uglyNamingFunction2];
}
- (void)function3:(DMParamsWrapper *)paramsWrapper
{
[self.oneCD tooManyParamsFunction3ParamOne:paramsWrapper.paramOne paramTwo:paramsWrapper.paramTwo paramThree:paramsWrapper.paramThree];
}
- (void)function4
{
[self.oneCD lowPerformanceFunction4];
}
@end
2.统一多个类的接口设计
某个功能的实现依赖多个外部系统(或者说类)。通过适配器模式,将它们的接口适配为统一的接口定义,然后就可以使用多态的特性来复用代码逻辑。
假设系统要对用户输入的文本内容做敏感词过滤,为了提高过滤的召回率,引入了多款第三方敏感词过滤系统,依次对用户输入的内容进行过滤,过滤掉尽可能多的敏感词。但是,每个系统提供的过滤接口都是不同的。这就意味着没法复用一套逻辑来调用各个系统。这个时候,就可以使用适配器模式,将所有系统的接口适配为统一的接口定义,这样就可以复用调用敏感词过滤的代码了。
// A敏感词过滤系统提供的方法
@interface DMASensitiveWordsFilter : NSObject
// text是原始文本,方法返回用***替换敏感词之后的文本
- (NSString *)filterSexyWords:(NSString *)text;
- (NSString *)filterPoliticalWords:(NSString *)text;
@end
@implementation DMASensitiveWordsFilter
- (NSString *)filterSexyWords:(NSString *)text
{
// 省略实现
return @"";
}
- (NSString *)filterPoliticalWords:(NSString *)text
{
// 省略实现
return @"";
}
@end
@interface DMBSensitiveWordsFilter : NSObject
- (NSString *)filter:(NSString *)text;
@end
@implementation DMBSensitiveWordsFilter
- (NSString *)filter:(NSString *)text
{
// 省略实现
return @"";
}
@end
@interface DMCSensitiveWordsFilter : NSObject
- (NSString *)filter:(NSString *)text mask:(NSString *)maskStr;
@end
@implementation DMCSensitiveWordsFilter
- (NSString *)filter:(NSString *)text mask:(NSString *)maskStr
{
// 省略实现
return @"";
}
@end
// 未使用适配器模式之前的代码: 代码的可测试性、扩展性不好
@interface DMRiskManagement : NSObject
- (NSString *)filterSensitiveWords:(NSString *)text;
@end
@interface DMRiskManagement ()
@property (nonatomic, strong) DMASensitiveWordsFilter *aFilter;
@property (nonatomic, strong) DMBSensitiveWordsFilter *bFilter;
@property (nonatomic, strong) DMCSensitiveWordsFilter *cFilter;
@end
@implementation DMRiskManagement
- (instancetype)init
{
if (self = [super init]) {
self.aFilter = [[DMASensitiveWordsFilter alloc] init];
self.bFilter = [[DMBSensitiveWordsFilter alloc] init];
self.cFilter = [[DMCSensitiveWordsFilter alloc] init];
}
return self;
}
- (NSString *)filterSensitiveWords:(NSString *)text
{
NSString *maskedText = [self.aFilter filterSexyWords:text];
maskedText = [self.aFilter filterPoliticalWords:maskedText];
maskedText = [self.bFilter filter:maskedText];
maskedText = [self.cFilter filter:maskedText mask:@"***"];
return maskedText;
}
@end
// 使用适配器模式进行改造
@protocol DMSensitiveWordFilter <NSObject>
- (NSString *)filter:(NSString *)text;
@end
// 使用适配器模式进行改造
@interface DMASensitiveWordsFilterAdaptor : NSObject <DMSensitiveWordFilter>
- (instancetype)initWithASensitiveWordsFilter:(DMASensitiveWordsFilter *)wordsFilter;
@end
@interface DMASensitiveWordsFilterAdaptor ()
@property (nonatomic, strong) DMASensitiveWordsFilter *aFilter;
@end
@implementation DMASensitiveWordsFilterAdaptor
- (instancetype)initWithASensitiveWordsFilter:(DMASensitiveWordsFilter *)wordsFilter
{
if (self = [super init]) {
self.aFilter = wordsFilter;
}
return self;
}
#pragma - DMSensitiveWordFilter 方法
- (NSString *)filter:(NSString *)text
{
NSString *maskedText = [self.aFilter filterSexyWords:text];
maskedText = [self.aFilter filterPoliticalWords:text];
return maskedText;
}
@end
// 使用适配器模式进行改造
@interface DMBSensitiveWordsFilterAdaptor : NSObject <DMSensitiveWordFilter>
- (instancetype)initWithBSensitiveWordsFilter:(DMBSensitiveWordsFilter *)wordsFilter;
@end
@interface DMBSensitiveWordsFilterAdaptor ()
@property (nonatomic, strong) DMBSensitiveWordsFilter *bFilter;
@end
@implementation DMBSensitiveWordsFilterAdaptor
- (instancetype)initWithBSensitiveWordsFilter:(DMBSensitiveWordsFilter *)wordsFilter
{
if (self = [super init]) {
self.bFilter = wordsFilter;
}
return self;
}
#pragma - DMSensitiveWordFilter 方法
- (NSString *)filter:(NSString *)text
{
NSString *maskedText = [self.bFilter filter:text];
return maskedText;
}
@end
// 使用适配器模式进行改造
@interface DMCSensitiveWordsFilterAdaptor : NSObject <DMSensitiveWordFilter>
- (instancetype)initWithCSensitiveWordsFilter:(DMCSensitiveWordsFilter *)wordsFilter;
@end
@interface DMCSensitiveWordsFilterAdaptor ()
@property (nonatomic, strong) DMCSensitiveWordsFilter *cFilter;
@end
@implementation DMCSensitiveWordsFilterAdaptor
- (instancetype)initWithCSensitiveWordsFilter:(DMCSensitiveWordsFilter *)wordsFilter
{
if (self = [super init]) {
self.cFilter = wordsFilter;
}
return self;
}
#pragma - DMSensitiveWordFilter 方法
- (NSString *)filter:(NSString *)text
{
NSString *maskedText = [self.cFilter filter:text mask:@"***"];
return maskedText;
}
@end
// 扩展性更好,更加符合开闭原则,如果添加一个新的敏感词过滤系统,
// 这个类完全不需要改动;而且基于接口而非实现编程,代码的可测试性更好。
@interface DMRiskManagement : NSObject
- (void)addSensitiveWordFilter:(id<DMSensitiveWordFilter>)sensitiveWordFilter;
- (NSString *)filter:(NSString *)text;
@end
@interface DMRiskManagement ()
@property (nonatomic, strong) NSMutableArray<id<DMSensitiveWordFilter>> *filters;
@end
@implementation DMRiskManagement
- (void)addSensitiveWordFilter:(id<DMSensitiveWordFilter>)sensitiveWordFilter
{
[self.filters addObject:sensitiveWordFilter];
}
- (NSString *)filter:(NSString *)text
{
NSString *maskedText = text;
for (id<DMSensitiveWordFilter> sensitiveWordFilter in self.filters) {
maskedText = [sensitiveWordFilter filter:maskedText];
}
return maskedText;
}
- (NSMutableArray<id<DMSensitiveWordFilter>> *)filters
{
if (_filters == nil) {
_filters = [[NSMutableArray<id<DMSensitiveWordFilter>> alloc] init];
}
return _filters;
}
@end
网友评论