适配器模式
1、 什么是适配器模式?
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
在 iOS 种,适配器有两种模式
- 面向对象的适配器
- 面向类的适配器
一般情况下,我使用的都是面向类的适配器的一种变种(用协议实现适配器),面向类的主要好处是易拓展、易重载并且整个适配器都只实现一个功能。
2、 适配器模式用在什么地方?
- 一般用在某个视图或者对象用在多个地方,但是这个视图或者对象的内容的数据原型不定。那么这个时候,就需要使用到适配器模式。
- 作用场合是希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。
- 视图复用,而数据 model 不同的情况。
例子:
有一天,你的产品经理过来跟你说需要一个 view ,view 里面有计算矩形面积的功能,然后你就利索的写了一个 width * height 返回计算的面积。
又过了几天,你的产品经理又过来跟你说,不但需要计算矩形面积,还得在另外一个地方计算原型的面积,不过视图长得一摸一样,于是乎,你考虑到可能后面还有平行四边形面积、梯形面积、三角形面积等,这时,就可以选择适配器模式处理这项业务。
3、 适配器使用
普通的面向类的适配器:
- 生成一个根适配器 RootAdapter 根适配器定义了返回的结果与读取数据的方法;
- 类适配器则通过继承根适配器生成不同的子类适配器;
- 子适配器导入模型,并通过子适配器得到转换后的结果。
面向类的适配器的变种:
- 定义一个协议 protocol,这个是为了实现转换后有统一的出口,所以必须存在;
- 在模型中直接引入协议,实现协议的内容进行转换;
4、总结
适配器模式主要的思想,在我看来就是多种入口、统一出口,通过一个可以代替多种入口对象的出口对象,并通过该出口对象得到最终的值的一种模式。也就是所谓的殊途同归。
不过需要保证的一点是出口必须保持长久的不变动,否则适配器便没有太大的意义。
所谓的变种的适配器也是同一道理:由于 iOS 中有协议(protocol)的存在,我去掉了适配器模式中间的适配器(adapter)对象,把协议本身(protocol.h)当作根适配器,把模型本身当作子类适配器使用,实现了适配器模式。
5. demo
所谓的变种适配器:
testProtocol.h
#import <Foundation/Foundation.h>
@protocol testProtocol <NSObject>
/** 姓名 */
- (NSString *)protocolName;
/** 地址 */
- (NSString *)protocolAddress;
/** 年龄 */
- (NSInteger)protocolAge;
@end
oldModel.h
#import <Foundation/Foundation.h>
#import "testProtocol.h"
@interface oldModel : NSObject <testProtocol>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *address;
@property (nonatomic, assign) NSInteger age;
@end
oldModel.m
#import "oldModel.h"
@implementation oldModel
- (NSInteger)protocolAge {
return self.age;
}
- (NSString *)protocolName {
return self.name;
}
- (NSString *)protocolAddress {
return self.address;
}
@end
newModel.h
#import <Foundation/Foundation.h>
#import "testProtocol.h"
@interface newModel : NSObject <testProtocol>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *address;
@property (nonatomic) NSInteger age;
@end
newModel.m
#import "newModel.h"
@implementation newModel
- (NSInteger)protocolAge {
return self.age+20;
}
- (NSString *)protocolName {
return [NSString stringWithFormat:@"姓名:%@",self.name];
}
- (NSString *)protocolAddress {
return [NSString stringWithFormat:@"地址:%@",self.address];
}
@end
ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
ViewController.m
#import "ViewController.h"
#import "oldModel.h"
#import "newModel.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)click1:(id)sender {
oldModel *m = [oldModel new];
m.age = 10;
m.address = @"guess";
m.name = @"9527";
[self loadData:m];
}
- (IBAction)click2:(id)sender {
newModel *m = [newModel new];
m.age = 10;
m.address = @"guess";
m.name = @"9527";
[self loadData:m];
}
- (void)loadData:(id<testProtocol>)data {
NSLog(@"%@ %@ %@",[data protocolName],@([data protocolAge]),[data protocolAddress]);
}
@end
click1 与 click2 是两个按钮的点击事件,从 sb 上直接拉取过来即可。这个例子中入口有两种 oldModel 和 newModel,通过协议使用同一个方法调用两种不同类型的对象。
网友评论