一圈纺、概念
1链沼、適配器模式的動機(jī)
? 目前手機(jī)的充電電壓是5伏到幾十伏不等默赂,但是我國標(biāo)準(zhǔn)居民用電電壓是220v,那么如何對手機(jī)進(jìn)行充電呢括勺?答案大家都知道缆八,使用充電器,也叫電源適配器疾捍。在軟件開發(fā)中奈辰,有時也存在類似這種不兼容的情況,我們也可以像引入一個電源適配器一樣引入一個稱之為適配器的角色來協(xié)調(diào)這些存在不兼容的結(jié)構(gòu)乱豆,這種設(shè)計(jì)方案即為適配器模式奖恰。
2、適配器模式的定義
? 適配器模式(Adapter Pattern):將一個接口轉(zhuǎn)換成客戶希望的另一個接口宛裕,使接口不兼容的那些類可以一起工作瑟啃,其別名為包裝器(Wrapper)。適配器模式既可以作為類結(jié)構(gòu)型模式揩尸,也可以作為對象結(jié)構(gòu)型模式蛹屿。
? 根據(jù)適配器類與適配者類的關(guān)系不同,適配器模式可分為對象適配器和類適配器兩種疲酌。在對象適配器模式中蜡峰,適配器與適配者之間是關(guān)聯(lián)關(guān)系;在類適配器模式中朗恳,適配器與適配者之間是繼承(或?qū)崿F(xiàn))關(guān)系湿颅。
3、適配器的3個角色
1)Target(目標(biāo)抽象類):目標(biāo)抽象類定義客戶所需接口粥诫,可以是一個抽象類或接口油航,也可以是具體類。
2)Adapter(適配器類):適配器可以調(diào)用另一個接口怀浆,作為一個轉(zhuǎn)換器谊囚,對Adaptee和Target進(jìn)行適配怕享,適配器類是適配器模式的核心,在對象適配器中镰踏,它通過繼承Target并關(guān)聯(lián)一個Adaptee對象使二者產(chǎn)生聯(lián)系函筋。
3)Adaptee(適配者類):適配者即被適配的角色,它定義了一個已經(jīng)存在的接口奠伪,這個接口需要適配末荐,適配者類一般是一個具體類代嗤,包含了客戶希望使用的業(yè)務(wù)方法华畏。
4媳荒、對象適配器-結(jié)構(gòu)圖
? 對象適配器使用較廣,結(jié)構(gòu)圖如圖所示:
5滤否、類適配器-結(jié)構(gòu)圖
? 適配器類實(shí)現(xiàn)了抽象目標(biāo)類接口Target脸狸,并繼承了適配者類,在適配器類的request()方法中調(diào)用所繼承的適配者類的specificRequest()方法藐俺,實(shí)現(xiàn)了適配炊甲。大部分情況下我們使用的是對象適配器,類適配器較少使用紊搪。
二蜜葱、對象適配器示例
1)先定義一個Electrical電器類,它有個charge()充電方法耀石,是目標(biāo)抽象類牵囤;
2)然后定義一個Television類,繼承自Electrical滞伟,是普通的電器揭鳞;
3)然后定義一個IphoneAdapter類蘋果電源適配器,繼承自Electrical類梆奈;
4)最后創(chuàng)建一個IphoneAdaptee類野崇,里面包含了具體的iPhone充電方法。
具體代碼如下:
Electrical類:
@interface Electrical: NSObject
- (void)charge;
@end
@implementation Electrical
- (void)charge {
}
@end
Television類:
@interface Television : Electrical
@end
@implementation Television
- (void)charge { //在子類實(shí)現(xiàn)方法
NSLog(@"電視充電220v");
}
@end
IphoneAdapter類:
@interface IphoneAdapter : Electrical
- (instancetype)initWithAdaptee:(IphoneAdaptee *)adaptee; //初始化方法亩钟,引入Adaptee
@end
@interface IphoneAdapter ()
@property(nonatomic, strong) IphoneAdaptee *adaptee;
@end
@implementation IphoneAdapter
- (instancetype)initWithAdaptee:(IphoneAdaptee *)adaptee {
self = [super init];
if (self) {
_adaptee = adaptee;
}
return self;
}
- (void)charge {
[self.adaptee iphoneCharge]; //實(shí)現(xiàn)轉(zhuǎn)發(fā)調(diào)用效果
}
@end
IphoneAdaptee類:
@interface IphoneAdaptee : NSObject
- (void)iphoneCharge;
@end
@implementation IphoneAdaptee
- (void)iphoneCharge {
NSLog(@"蘋果充電5v");
}
@end
運(yùn)行代碼:
- (void)viewDidLoad {
[super viewDidLoad];
Television *tv = [Television new];
[tv charge];
IphoneAdaptee *adaptee = [IphoneAdaptee new];
IphoneAdapter *adapter = [[IphoneAdapter alloc] initWithAdaptee:adaptee];
[adapter charge];
}
打印結(jié)果:
電視充電220v
蘋果充電5v
三乓梨、類適配器示例
1)和上面類似,先創(chuàng)建一個Electrical協(xié)議清酥,有一個charge()方法扶镀,表示目標(biāo)抽象類;
2)然后創(chuàng)建一個Television類焰轻,遵循Electrical協(xié)議臭觉;
3)然后創(chuàng)建一個IphoneAdaptee類,有iphoneCharge()方法,表示適配者蝠筑;
4)最后創(chuàng)建IphoneAdapter類狞膘,繼承自IphoneAdaptee類,并遵循Electrical協(xié)議什乙,表示適配器挽封。
具體代碼如下:
Electrical協(xié)議:
@protocol Electrical <NSObject>
- (void)charge;
@end
Television類:
@interface Television : NSObject<Electrical>
@end
@implementation Television
- (void)charge {
NSLog(@"電視充電220v");
}
@end
IphoneAdaptee類:
@interface IphoneAdaptee : NSObject
- (void)iphoneCharge;
@end
@implementation IphoneAdaptee
- (void)iphoneCharge {
NSLog(@"蘋果充電5v");
}
@end
IphoneAdapter類:
@interface IphoneAdapter : IphoneAdaptee<Electrical>
@end
@implementation IphoneAdapter
- (void)charge {
[self iphoneCharge];
}
@end
運(yùn)行代碼:
- (void)viewDidLoad {
[super viewDidLoad];
Television *tv = [Television new];
[tv charge];
IphoneAdapter *adapter = [IphoneAdapter new];
[adapter charge];
}
打印結(jié)果:
電視充電220v
蘋果充電5v
四、缺省適配器模式
? 缺省適配器模式是適配器模式的一種變體稳强,其應(yīng)用也較為廣泛场仲。
1和悦、缺省適配器模式的定義
? 缺省適配器模式(Default Adapter Pattern):當(dāng)不需要實(shí)現(xiàn)一個接口所提供的所有方法時退疫,可先設(shè)計(jì)一個抽象類實(shí)現(xiàn)該接口,并為接口中每個方法提供一個默認(rèn)實(shí)現(xiàn)(空方法)鸽素,那么該抽象類的子類可以選擇性地覆蓋父類的某些方法來實(shí)現(xiàn)需求褒繁,它適用于不想使用一個接口中的所有方法的情況,又稱為單接口適配器模式馍忽。
2棒坏、缺省適配器模式的3個角色
1)ServiceInterface(適配者接口):通常在該接口中聲明了大量的方法。
2)AbstractServiceClass(缺省適配器類):它是缺省適配器模式的核心類遭笋,使用空方法的形式實(shí)現(xiàn)了在ServiceInterface接口中聲明的方法坝冕,通常將它定義為抽象類。
3)ConcreteServiceClass(具體業(yè)務(wù)類):它是缺省適配器類的子類瓦呼,根據(jù)需要有選擇性地覆蓋在適配器類中定義的方法喂窟。
3、缺省適配器模式的結(jié)構(gòu)圖
4央串、Demo示例
1)先創(chuàng)建一個AnimalProtocol協(xié)議磨澡,里面定義了幾個動物的方法,是ServiceInterface適配者接口质和;
2)然后創(chuàng)建一個抽象類Animal稳摄,遵循AnimalProtocol協(xié)議,并實(shí)現(xiàn)所有的方法-空方法饲宿,是AbstractServiceClass缺省適配器類厦酬;
3)最后創(chuàng)建一個Fish類,繼承自Animal類瘫想,并實(shí)現(xiàn)了fish的方法仗阅,是ConcreteServiceClass具體業(yè)務(wù)類。
具體代碼如下:
AnimalProtocol類:
@protocol AnimalProtocol <NSObject>
- (void)eat;
- (void)run;
- (void)swim;
@end
Animal類:
@interface Animal : NSObject <AnimalProtocol>
@end
@implementation Animal
- (void)eat {}
- (void)run {}
- (void)swim {}
@end
Fish類:
@interface Fish : Animal
@end
@implementation Fish
- (void)eat {
NSLog(@"魚兒吃魚餌");
}
- (void)swim {
NSLog(@"魚兒能游泳");
}
@end
運(yùn)行代碼:
- (void)viewDidLoad {
[super viewDidLoad];
Fish *fish = [Fish new];
[fish eat];
[fish swim];
}
打印結(jié)果:
魚兒吃魚餌
魚兒能游泳
五殿托、總結(jié)
? 適配器模式將現(xiàn)有接口轉(zhuǎn)化為客戶類所期望的接口霹菊,實(shí)現(xiàn)了對現(xiàn)有類的復(fù)用,它是一種使用頻率非常高的設(shè)計(jì)模式,在軟件開發(fā)中得以廣泛應(yīng)用旋廷。
1鸠按、優(yōu)點(diǎn)
? 對象適配器模式和類適配器模式都有的優(yōu)點(diǎn):
1、將目標(biāo)類和適配者類解耦饶碘,通過引入一個適配器類來重用現(xiàn)有的適配者類目尖,無須修改原有結(jié)構(gòu)。
2扎运、增加了類的透明性和復(fù)用性瑟曲,將具體的業(yè)務(wù)實(shí)現(xiàn)過程封裝在適配者類中,對于客戶端類而言是透明的豪治,而且提高了適配者的復(fù)用性洞拨,同一個適配者類可以在多個不同的系統(tǒng)中復(fù)用。
3负拟、靈活性和擴(kuò)展性好烦衣,通過使用配置文件,可以很方便地更換適配器掩浙,也可以在不修改原有代碼的基礎(chǔ)上增加新的適配器類花吟,完全符合“開閉原則”。
? 類適配器還有的優(yōu)點(diǎn):
? 由于適配器類是適配者類的子類厨姚,因此可以在適配器類中置換一些適配者的方法衅澈,使得適配器的靈活性更強(qiáng)。
? 對象適配器模式還有的優(yōu)點(diǎn):
1谬墙、一個對象適配器可以把多個不同的適配者適配到同一個目標(biāo)今布。
2、可以適配一個適配者的子類芭梯,由于適配器和適配者之間是關(guān)聯(lián)關(guān)系险耀,根據(jù)“里氏代換原則”,適配者的子類也可通過該適配器進(jìn)行適配玖喘。
2甩牺、缺點(diǎn)
? 類適配器缺點(diǎn):
1、對于Java累奈、C#等不支持多重類繼承的語言贬派,一次最多只能適配一個適配者類,不能同時適配多個適配者澎媒。
2搞乏、適配者類不能為最終類,如在Java中不能為final類戒努,C#中不能為sealed類请敦。
3、 在Java、C#等語言中侍筛,類適配器模式中的目標(biāo)抽象類只能為接口萤皂,不能為類,其使用有一定的局限性匣椰。
? 對象適配器缺點(diǎn):
? 與類適配器模式相比裆熙,要在適配器中置換適配者類的某些方法比較麻煩。如果一定要置換掉適配者類的一個或多個方法禽笑,可以先做一個適配者類的子類入录,將適配者類的方法置換掉,然后再把適配者類的子類當(dāng)做真正的適配者進(jìn)行適配佳镜,實(shí)現(xiàn)過程較為復(fù)雜僚稿。
3、適用場景
1邀杏、系統(tǒng)需要使用一些現(xiàn)有的類贫奠,而這些類的接口(如方法名)不符合系統(tǒng)的需要,甚至沒有這些類的源代碼望蜡。
2、想創(chuàng)建一個可以重復(fù)使用的類拷恨,用于與一些彼此之間沒有太大關(guān)聯(lián)的一些類脖律,包括一些可能在將來引進(jìn)的類一起工作。
4腕侄、APP應(yīng)用舉例
? Android的ListView就是通過adapter來實(shí)現(xiàn)所有的布局和事件操作的小泉。
Demo地址:iOS-Design-Patterns