iOS設(shè)計模式-適配器模式

1. 什么是適配器

適配器模式(Adapter Pattern) 定義

Convert the interface of a class into another interface clients expect.Adapter lets classeswork together that couldn't otherwise because of incompatible interfaces.(將一個類的接口變換成客戶端所期待的另一種接口悠鞍,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。)

有時候也稱包裝樣式或者包裝(wrapper)模燥。將一個類的接口轉(zhuǎn)接成用戶所期待的咖祭。一個適配使得因接口不兼容而不能在一起工作的類能在一起工作,做法是將類自己的接口包裹在一個已存在的類中蔫骂。

2. 角色組成

適配器設(shè)計模型主要由三個角色組成么翰,分別是:

  • 適配器角色(adapter)-- 將已有接口轉(zhuǎn)換成目標(biāo)接口
  • 目標(biāo)角色(target) -- 目標(biāo)可以是具體的或抽象的類,也可以是接口
  • 源角色或被適配者(adaptee) -- 已有接口

3. 適配器類型與實例

適配器類型可以分為三種:

  • 類適配器模式
  • 對象適配器模式
  • 接口適配器模式或缺省適配器模式

接下來我們以手機充電適配器為例子辽旋,手機充電需要的電壓一般為5V浩嫌。國內(nèi)家用供電為220V,而日本則是110V补胚,針對不同地區(qū)的電壓码耐,我們需要一個適配器,這樣才能對手機進行充電糖儡。

我們先定義電源基礎(chǔ)類

//  Power.h
#import <Foundation/Foundation.h>
@interface Power : NSObject
//輸出電壓
- (NSInteger)outputValue;
@end


// Power.m
#import "Power.h"
@implementation Power
- (NSInteger)outputValue {
    return 0;
}
@end

定義好適配手機5V電壓的協(xié)議

// PowerPhoneNeedInterface.h

#import <Foundation/Foundation.h>
@protocol PowerPhoneNeedInterface <NSObject>
@required
- (NSInteger)outputPowerPhone;
@end
3.1 類適配器模式

類適配器模式是通過繼承被適配者來實現(xiàn)適配功能伐坏,UML關(guān)系圖如下:


類適配器模式

代碼如下:
我們先定義一個被適配者角色(中國家用供電):

// PowerACChina.h

#import "Power.h"
@interface PowerACChina : Power
@end


// PowerACChina.m

#import "PowerACChina.h"
@implementation PowerACChina
- (NSInteger)outputValue {
    return 220;
}
@end

接下來可以定義一個適配器(中國家用供電),來滿足手機充電輸出5V的要求

//PowerAdapterChina.h

#import "PowerACChina.h"
#import "PowerPhoneNeedInterface.h"
@interface PowerAdapterChina : PowerACChina<PowerPhoneNeedInterface>
@end


//PowerAdapterChina.m

#import "PowerAdapterChina.h"
@implementation PowerAdapterChina
- (NSInteger)outputPowerPhone {
    return [self outputValue] / 44;
}
@end

這里握联,我們的適配器桦沉,繼承于被適配角色并且實現(xiàn)目標(biāo)角色每瞒,這樣通過實現(xiàn)目標(biāo)角色中的方法調(diào)用被適配角色中的方法進行運算,從而達到適配的效果纯露。接下來我們進行調(diào)用測試

+ (void)test1 {
    PowerAdapterChina *adapter = [[PowerAdapterChina alloc] init];
    NSInteger inputPower = [adapter outputPowerPhone];
    NSLog(@"source output power = %ld\n adpater output power = %ld", [adapter outputValue], inputPower);
}

運行結(jié)果:

source output power = 220 
adpater output power = 5

從代碼中我們可以看到剿骨,其實適配器做的主要工作就是為了讓被適配角色的API能夠滿足目標(biāo)角色的要求進行調(diào)用,適配器在中間做的是一個類似的中轉(zhuǎn)作用埠褪,并且不影響源角色和目標(biāo)角色原有的功能和邏輯浓利。

3.2 對象適配器模式

對象適配器模式適配器通過持有被適配角色實例,對接口進行適配钞速,UML圖如下:


對象適配器

接下來我們通過代碼實現(xiàn)下贷掖。

被適配者角色,依然是 PowerACChina, 這里不再進行重復(fù)闡述渴语。

接下來我們來創(chuàng)建一個新的適配器 PowerAdapterChina2


// PowerAdapterChina2.h

#import <Foundation/Foundation.h>
#import "PowerPhoneNeedInterface.h"
#import "PowerACChina.h"

@interface PowerAdapterChina2 : NSObject <PowerPhoneNeedInterface>
@property (nonatomic, strong) PowerACChina *power;
- (instancetype)initWithChinaPower:(PowerACChina *)power;
@end



// PowerAdapterChina2.m

#import "PowerAdapterChina2.h"
#import "PowerACChina.h"
@implementation PowerAdapterChina2
- (instancetype)initWithChinaPower:(PowerACChina *)power {
    self = [super init];
    if (self) {
        _power = power;
    }
    return self;
}
- (NSInteger)outputPowerPhone {
    return [self.power outputValue] / 44;
}
@end

有代碼可以看到苹威,我們需要在適配器PowerAdapterChina2通過持有被適配者調(diào)用源API達到轉(zhuǎn)換成滿足目標(biāo)API的效果, 我們寫個測試方法進行驗證

//對象適配
+ (void)test2 {
    PowerACChina *power = [[PowerACChina alloc] init];
    PowerAdapterChina2 *adapter = [[PowerAdapterChina2 alloc] initWithChinaPower:power];
    NSInteger inputPower = [adapter outputPowerPhone];
    NSLog(@"source output power = %ld\n adpater output power = %ld", [power outputValue], inputPower);
}
source output power = 220 
adpater output power = 5

我們的測試時在創(chuàng)建適配器時驾凶,傳入?yún)?shù)為被適配角色實例牙甫,通過適配器,輸出目標(biāo)

3.3 接口適配器模式

接口適配器模式又成缺省適配器模式调违,適配器默認實現(xiàn)了所有目標(biāo)角色接口窟哺。并且適配器可以通過持有不同的被適配者實例,在內(nèi)部進行轉(zhuǎn)化為目標(biāo)角色API技肩,相對應(yīng)前兩種適配模式更加靈活且易于拓展且轨。
UML關(guān)系圖如下:


接口適配器

代碼如下:
我們再建一個被適配者角色(日本家用供電) PowerACJapan

// PowerACJapan.h

#import "Power.h"
@interface PowerACJapan : Power
@end



//PowerACJapan.h

#import "PowerACJapan.h"
@implementation PowerACJapan
- (NSInteger)outputValue {
    return 110;
}
@end

定義接口適配器


// PowerAdapterAll.h
#import <Foundation/Foundation.h>
#import "Power.h"
#import "PowerPhoneNeedInterface.h"
@interface PowerAdapterAll : NSObject<PowerPhoneNeedInterface>
@property (nonatomic, strong) Power *power;
- (instancetype)initWithPower:(Power *)power;
@end


// PowerAdapterAll.m
#import "PowerAdapterAll.h"
#import "Power.h"
@implementation PowerAdapterAll
- (instancetype)initWithPower:(Power *)power {
    self = [super init];
    if (self) {
        _power = power;
    }
    return self;
}
- (NSInteger)outputPowerPhone {
    NSInteger outputPower = [self.power outputValue];
    NSInteger sta = outputPower / 5;
    if ([self.power isKindOfClass:PowerACJapan.class]) {
        sta = 22;
    } else if ([self.power isKindOfClass:PowerACChina.class]) {
        sta = 44;
    }
    return outputPower / sta;
}
@end

調(diào)用測試:

//接口適配
+ (void)test3 {
    PowerACChina *power = [[PowerACChina alloc] init];
    PowerAdapterAll *adapter = [[PowerAdapterAll alloc] initWithPower:power];
    NSInteger inputPower = [adapter outputPowerPhone];
    NSLog(@"source output power = %ld\n adpater output power = %ld", [adapter.power outputValue], inputPower);
    
    PowerACJapan *power2 = [[PowerACJapan alloc] init];
    PowerAdapterAll *adapter2 = [[PowerAdapterAll alloc] initWithPower:power2];
    NSInteger inputPower2 = [adapter2 outputPowerPhone];
    NSLog(@"source output power = %ld\n adpater output power = %ld", [adapter2.power outputValue], inputPower2);
}

運行結(jié)果

source output power = 220
 adpater output power = 5
source output power = 110
 adpater output power = 5

如上代碼,在適配器角色中亩鬼,我們提供多個適配器角色能夠傳入不同被適配者角色能力(這里傳入的為Power子類)殖告,通過具體被適配者角色的實例使用抽象的電源引用阿蝶,適配器類實現(xiàn)于目標(biāo)角色并實現(xiàn)目標(biāo)角色的方法雳锋,在方法體中,我們進行邏輯處理羡洁,將輸入的電壓進行適配為5V電壓玷过,從而達到萬能適配的效果。

4. 分析

  • 復(fù)用性:系統(tǒng)需要使用已經(jīng)存在的類筑煮,功能符合系統(tǒng)要求辛蚊,但這個類的接口不符合系統(tǒng)的需求,通過適配器模式解決不兼容的問題真仲,使這些功能類得到復(fù)用袋马。
  • 耦合性:一定程度上的解耦
  • 過多地使用適配器,增加系統(tǒng)理解難度秸应。

適用場景

  • 我們在使用第三方的類庫虑凛,或者說第三方的API的時候碑宴,我們通過適配器轉(zhuǎn)換來滿足現(xiàn)有系統(tǒng)的使用需求。

  • 你想使用現(xiàn)有的一些類的功能桑谍,但其接口不匹配你的要求延柠,你又不想修改原始類的情況

  • 需要建立一個可以重復(fù)使用的類,用于一些彼此關(guān)系不大的類锣披,并易于擴展贞间,以便于面對將來會出現(xiàn)的類。

  • 需要一個統(tǒng)一的輸出接口雹仿,但是輸入類型卻不可預(yù)知增热。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市胧辽,隨后出現(xiàn)的幾起案子钓葫,更是在濱河造成了極大的恐慌,老刑警劉巖票顾,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件础浮,死亡現(xiàn)場離奇詭異,居然都是意外死亡奠骄,警方通過查閱死者的電腦和手機豆同,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來含鳞,“玉大人影锈,你說我怎么就攤上這事〔醣粒” “怎么了鸭廷?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長熔吗。 經(jīng)常有香客問我辆床,道長,這世上最難降的妖魔是什么桅狠? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任讼载,我火速辦了婚禮,結(jié)果婚禮上中跌,老公的妹妹穿的比我還像新娘咨堤。我一直安慰自己,他們只是感情好漩符,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布一喘。 她就那樣靜靜地躺著,像睡著了一般嗜暴。 火紅的嫁衣襯著肌膚如雪凸克。 梳的紋絲不亂的頭發(fā)上铝侵,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機與錄音触徐,去河邊找鬼咪鲜。 笑死,一個胖子當(dāng)著我的面吹牛撞鹉,可吹牛的內(nèi)容都是我干的疟丙。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼鸟雏,長吁一口氣:“原來是場噩夢啊……” “哼享郊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起孝鹊,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤炊琉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后又活,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體苔咪,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年柳骄,在試婚紗的時候發(fā)現(xiàn)自己被綠了团赏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡耐薯,死狀恐怖舔清,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情曲初,我是刑警寧澤体谒,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站臼婆,受9級特大地震影響抒痒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜目锭,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一评汰、第九天 我趴在偏房一處隱蔽的房頂上張望纷捞。 院中可真熱鬧痢虹,春花似錦、人聲如沸主儡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽糜值。三九已至丰捷,卻和暖如春坯墨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背病往。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工捣染, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人停巷。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓耍攘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親畔勤。 傳聞我的和親對象是個殘疾皇子蕾各,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345