第一次写博客啊,写的不好的地方请多指教哦~
在介绍适配器模式之前,先来看一个经典的栗子啊~
每一个国家的额定电压都不一样,但是我们的手机额定充电电压是一定的。那假如我们每一次去到不同的国家,难道都要买一个适配手机额定电压的充电器嘛???当然是不用的,拿苹果的充电器来说,它可以接受的输入电压不是一成不变的,而是有一个范围来适应不同情况下的输入电压,但是输出电压是固定的。
可以这样来理解,将目标设备看做 ‘接口’,各种电压相当于 ‘功能相同的类’,电源适配器就是 ‘需要实现的适配器类’。
在iOS开发中,当输入数据的类型稍有差异的时候,可能需要修改原来写好的代码,也可能会有CRASH。。。这时候,就是适配器模式派上用场的时候啦~它可以在不修改或者极少修改代码的情况下,适应输入数据类型不一。
话不多说,上代码~~~~
1.直接赋值
//CardView.h
@interface CardView : UIView
//名字
@property (nonatomic,strong) NSString *nameStr;
//分割线条颜色
@property (nonatomic,strong) UIColor *linecolor;
//电话
@property (nonatomic,strong) NSString *phoneNumberStr;
- (void)loadData:(Model*)data;
@end
CardView.m实现部分就不写啦~~~
- (void)viewDidLoad {
[super viewDidLoad];
CardView *cardView = [[CardView alloc]initWithFrame:FRAME];
cardView.center = self.view.center;
//直接赋值
cardView.nameStr = @"MM";
cardView.linecolor = [UIColor redColor];
cardView.phoneNumberStr = @"12345678910";
[self.view addSubview:cardView];
}
采用直接赋值的方法当然是最简单的,但假如 linecolor 是一个NSString类对象 , 直接赋值会出错,
但是大片的修改已经写好的代码也不是一个好办法。
最无语的情况大概就是你修改好了,linecolor又是UIColor类对象时,难道还要改回去嘛???
EXO ME???
2.对象赋值
新创建一个Model类,继承于NSObject。
//Model.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface Model : NSObject
@property (nonatomic,strong) NSString *nameStr;
@property (nonatomic,strong) UIColor *linecolor;
@property (nonatomic,strong) NSString *phoneNumberStr;
@end
有一些童鞋可能会说,这有变化嘛?和CardView.h没啥区别啊~现在看来是没区别,但是马上就有啦~
在CardView.h加上- (void)loadData:(Model*)data; 这个方法并在 .m 文件实现。
//CardView.m实现上述方法
- (void)loadData:(Model *)data{
self.nameStr = data.nameStr;
self.linecolor = data.linecolor;
self.phoneNumberStr = data.phoneNumberStr;
}
//ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
CardView *cardView = [[CardView alloc]initWithFrame:FRAME];
cardView.center = self.view.center;
//对象赋值
Model *model = [[Model alloc]init];
model.nameStr = @"MM";
model.linecolor = [UIColor redColor];
model.phoneNumberStr = @"12345678910";
[cardView loadData:model];
[self.view addSubview:cardView];
}
看到这里,有一些童鞋肯定就要问啦,那这种和直接赋值没啥区别,改一个数据还不是照样用不了。对啦~接下来就是我们的重头戏啊---
第一步:声明一个协议,在此我将它命名为CardViewProtocol,并且在该协议中有三个方法:
#import <Foundation/Foundation.h>
@protocol CardViewAdapterProtocol <NSObject>
- (NSString *)nameStr;
- (UIColor *)lineColor;
- (NSString *)phoneNumberStr;
@end
第二步:声明一个适配器的类,在此命名为CardViewAdapter类,需要与输入的对象建立联系。
.h文件
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "CardViewAdapterProtocol.h"
@interface CardViewAdapter : NSObject<CardViewAdapterProtocol>
//输入对象
@property (nonatomic, weak) id data;
//声明该方法与输入的对象建立联系
- (instancetype)initWithData:(id)data;
@end
.m文件
#import "CardViewAdapter.h"
@implementation CardViewAdapter
- (instancetype)initWithData:(id)data{
self = [super init];
if (self) {
self.data = data;
}
return self;
}
//空实现CardViewProtocol里的方法
- (NSString *)nameStr{
return nil;
}
- (UIColor *)lineColor{
return nil;
}
- (NSString *)phoneNumberStr{
return nil;
}
@end
第三步:在CardView类中加载实现了CardViewProtocol协议的数据
.h文件
- (void)loadData:(id <BusinessCardAdapterProtocol>)data;
- (void)loadData:(id<CardViewAdapterProtocol>)data{
self.nameStr = [data nameStr];
self.linecolor = [data lineColor];
self.phoneNumberStr = [data phoneNumberStr];
}
第四步:拿刚刚的Model类为例,建立一个Model类适配器,继承于CardViewAdapter,名为ModelAdapter类,在 .m 文件中重写父类的方法,以实现数据的加载。
#import "ModelAdapter.h"
#import "Model.h"
@implementation ModelAdapter
- (instancetype)initWithData:(id)data{
self = [super init];
if (self) {
self.data = data;
}
return self;
}
- (NSString *)nameStr{
Model *data = self.data;
return data.nameStr;
}
- (UIColor *)lineColor{
Model *data = self.data;
return data.linecolor;
}
- (NSString *)phoneNumberStr{
Model *data = self.data;
return data.phoneNumberStr;
}
@end
最后,要在ViewController里面实现啦~
- (void)viewDidLoad {
[super viewDidLoad];
CardView *cardView = [[CardView alloc]initWithFrame:FRAME];
cardView.center = self.view.center;
//对象赋值
Model *model = [[Model alloc]init];
model.nameStr = @"MM";
model.linecolor = [UIColor redColor];
model.phoneNumberStr = @"12345678910";
//与输入建立联系
CardViewAdapter *modelAdapter = [[CardViewAdapter alloc]initWithData:model];
//与输出建立联系
[cardView loadData:modelAdapter];
[self.view addSubview:cardView];
}
最开始的时候说,如果有一个输入的参数类型不一致,肿么办?用这种方法就很容易解决啦~我们只需要对相应类的适配器中,对父类方法重写时,将输入的数据类型转化为我们想要的数据类型即可。
举个栗子啦,lineColor 是 NSString类型。
- (UIColor *)lineColor {
NewCardModel *data = self.data;
// todo
if ([data.colorHexString isEqualToString:@"red"]) {
return [UIColor redColor];
} else {
return [UIColor black];
}
}
像这样,一个类有一个适配器的叫做类适配器,对应的就肯定有对象适配器啦。
假设现在有两种类型的输入参数(一个类名为Model,一个类名为NewModel),我们要建立一个对象适配器,就把它叫做ObjectAdapter好了。当然,与类适配器相似,仍然继承于CardViewAdapter,还是在重写父类的方法时,稍有不同。
#import "ObjectAdapter.h"
#import "Model.h"
#import "NewModel.h"
@implementation ObjectAdapter
- (instancetype)initWithData:(id)data {
self = [super init];
if (self) {
self.data = data;
}
return self;
}
- (NSString *)nameStr {
NSString *nameStr = nil;
if ([self.data isMemberOfClass:[Model class]]) {
Model *model = self.data;
nameStr = model.nameStr;
} else if ([self.data isMemberOfClass:[NewModel class]]) {
NewModel *model = self.data;
nameStr = model.nameStr;
}
return nameStr;
}
//依次实现。。。
@end
当输入数据的类型过多时,采用对象适配器会让代码冗杂,一般情况下,一个类一个适配器比较好。
看到这里,很多童鞋会说,我用直接赋值才三行代码,你这一个适配器又是整这又是整那的,还那么的不好理解。对于没有啥经验的开发者就像我来说,这样的写法肯定是不好懂,但是它的可移植性高。说不定你的下一个工程也刚好会用到这个呢,这种情况你只需要稍作修改就可以的啊。所以,对于像我这样的小白,我觉得还是可以采用这种方法的,毕竟还是要提高编程能力的嘛~~~哈哈哈~~~
到这里,我就介绍完毕啦~第一次写,不好的地方请各位亲指点,一起学习一起进步嘛~~~谢谢大家~撒花~~~手动笔芯~~~