(-) 提出問題
朋友們在開發(fā)中有沒有遇到過這種情況:開發(fā)中寫了一個視圖控件兜材,雖然這個控件只是一個展示類的,并沒有什么交互。但是在項目好幾個地方都用到了這個控件了,你在給這個視圖控件負值的時候是怎么做的呢最楷?
是不是這么寫的呢?
-(void)laodData:(ItemModel*)model ;
這么寫沒有錯待错,而且感覺很簡單籽孙。但是有兩點不好:
- 視圖根數(shù)據(jù)模型有耦合,視圖類引入了模型火俄。
2.當你在項目里其他的地方用到了這個視圖類犯建,而且對應的模型不再是ItemModel了,而是一個新的模型瓜客,比如說ContentModel胎挎,這個時候你要再寫一個初始化方法嗎?類似:
-(void)laodData:(ContentModel*)model ;
這樣寫似乎也沒有錯忆家,但是如多更多地方用了怎么辦?
你有沒有想過德迹,我不同的地方用到一個控件芽卿,為什么要改寫好的視圖控件呢?有沒有別的方法能讓我寫的視圖控件獨立出來胳搞,不和數(shù)據(jù)模型產(chǎn)生耦合呢卸例?這就用到了設計模式中的一個適配器模式了称杨。
(二 )適配器設計模式 簡介
將一個類的接口轉(zhuǎn)換成客戶希望的另外一個接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作筷转。
適用場景:
1姑原、已經(jīng)存在的類的接口不符合我們的需求;
2呜舒、創(chuàng)建一個可以復用的類锭汛,使得該類可以與其他不相關(guān)的類或不可預見的類(即那些接口可能不一定兼容的類)協(xié)同工作;
3袭蝗、在不對每一個都進行子類化以匹配它們的接口的情況下唤殴,使用一些已經(jīng)存在的子類。
(三 )使用適配器模式重構(gòu)代碼
下面從一個例子中看下適配器的寫法:
項目中有一個視圖類到腥,展示一個效果朵逝,前面是一個圖片,圖片的后面是一段文字乡范,這個控件在項目里多處使用配名,并且對應不同的數(shù)據(jù)模型:效果如下
第1步 修改視圖接收數(shù)據(jù)方法
把視圖控件的初始化數(shù)據(jù)改為接收一個遵守某個協(xié)議的數(shù)據(jù)
-(void)loadData:(id <ContentViewAdapterProtocol>)data{
self.image = [data image];
self.contentStr = [data contentStr];
}
不管傳過來的數(shù)據(jù)是什么類型,只要服從這個協(xié)議晋辆,實現(xiàn)協(xié)議里的方法渠脉,視圖就能處理這個數(shù)據(jù)了
第2步 實現(xiàn)這個協(xié)議
新建也個協(xié)議文件
@protocol ContentViewAdapterProtocol <NSObject>
-(UIImage*)image;
-(NSString*)contentStr;
@end
第3步 創(chuàng)建根適配器類
類遵守上面的協(xié)議,并實現(xiàn)協(xié)議的方法栈拖,但是只是空實現(xiàn)
-(UIImage*)image{
return nil;
}
-(NSString*)contentStr{
return nil;
}
添加初始化數(shù)據(jù)方法
- (instancetype)initWithData:(id)data;
這樣這個適配器就完成了连舍。
第4步 針對不同的類創(chuàng)建適配器
使用適配器的時候分為類適配器和對象適配器,類適配器是針對每一個數(shù)據(jù)類創(chuàng)建一個適配器涩哟。創(chuàng)建的這個適配器類繼承于上面的那個根適配器類索赏。如果要適配另一個數(shù)據(jù)類就需要再新建一個新的適配器類來適配。
新建真對ItemModel的適配器:
#import "ItemModelAdeapter.h"
#import "ItemModel.h"
@implementation ItemModelAdeapter
- (instancetype)initWithData:(id)data{
self = [super init];
if (self) {
self.data = data;
}
return self;
}
-(UIImage*)image{
ItemModel *model = self.data;
return model.image;
}
-(NSString*)contentStr{
ItemModel *model = self.data;
return model.conntentStr;
}
對象適配器是只創(chuàng)建一個適配器類贴彼,繼承于上面的根適配器潜腻。然后根據(jù)不同的數(shù)據(jù)類返回不同的數(shù)據(jù):
#import "ModelAdapter.h"
#import "ItemModel.h"
#import "ContenModel.h"
//對象適配器
@implementation ModelAdapter
- (instancetype)initWithData:(id)data{
self = [super init];
if (self) {
self.data = data;
}
return self;
}
-(UIImage*)image{
if ([self.data isMemberOfClass:[ContenModel class]]) {
ContenModel *model = self.data;
return [UIImage imageNamed:model.imageName];
}else{
ItemModel *model = self.data;
return model.image;
}
}
-(NSString*)contentStr{
if ([self.data isMemberOfClass:[ContenModel class]]) {
ContenModel *model = self.data;
return model.conntentStr;
}else{
ItemModel *model = self.data;
return model.conntentStr;
}
}
對象適配器的好處是在一個類里處理不同的數(shù)據(jù),類會少一些器仗。但是如果要適配的類太多就會顯得很復雜融涣,而對象適配器適配方法分散,類比較多精钮。
第5步 使用適配器
類適配器 適配兩個類
第一個
ContenModel *contenModel = [[ContenModel alloc]init];
contenModel.conntentStr = @"時間:10:32:12";
contenModel.imageName = @"shijian";
ContentViewAdapter *modelAdapter = [[ContentModelAdeapter alloc]initWithData:contenModel];
ContentView *contentView = [[ContentView alloc]initWithFrame:CGRectMake(100, 100, 200, 20)];
[contentView loadData:modelAdapter];
[self.view addSubview:contentView];
第二個
ItemModel *itemModel = [[ItemModel alloc]init];
itemModel.conntentStr = @"心率:100次";
itemModel.image = [UIImage imageNamed:@"mapHeaderIcon"];
ContentViewAdapter *modelAdapter1 = [[ItemModelAdeapter alloc]initWithData:itemModel];
ContentView *contentView1 = [[ContentView alloc]initWithFrame:CGRectMake(100, 200, 200, 20)];
[contentView1 loadData:modelAdapter1];
[self.view addSubview:contentView1];
對象適配器
第一個
ItemModel *itemModel1 = [[ItemModel alloc]init];
itemModel1.conntentStr = @"心率:100次";
itemModel1.image = [UIImage imageNamed:@"mapHeaderIcon"];
ContentViewAdapter *modelAdapter2 = [[ModelAdapter alloc]initWithData:itemModel];
ContentView *contentView2 = [[ContentView alloc]initWithFrame:CGRectMake(100, 300, 200, 20)];
[contentView2 loadData:modelAdapter2];
[self.view addSubview:contentView2];
第二個
ContenModel *contenModel2 = [[ContenModel alloc]init];
contenModel2.conntentStr = @"時間:10:32:12";
contenModel2.imageName = @"shijian";
ContentViewAdapter *modelAdapter3 = [[ModelAdapter alloc]initWithData:contenModel];
ContentView *contentView3 = [[ContentView alloc]initWithFrame:CGRectMake(100, 400, 200, 20)];
[contentView3 loadData:modelAdapter3];
[self.view addSubview:contentView3];
(四)適配器模式的缺點
優(yōu)點:
解耦合威鹿,讓視圖類不合數(shù)據(jù)類產(chǎn)生耦合,使視圖類更加獨立轨香。 新增加數(shù)據(jù)類的時候不需要修改視圖類忽你。
缺點:
會新增加很多類,使系統(tǒng)更凌亂臂容,代碼可讀性更弱了科雳。
所以大家酌情使用
(五)鳴謝
這篇文章是看過 YouXianMing老師 的教程后根蟹,得到的啟發(fā)并重構(gòu)自己項目代碼后寫的總結(jié)。希望對大家有點幫助糟秘。在此感謝YouXianMing老師简逮。