前言
??前段時(shí)間看了《Head First設(shè)計(jì)模式》這本書,雖然沒有看完,但常用的設(shè)計(jì)模式基本都看了一遍。剛開始看完基本都能理解,也能體會(huì)到設(shè)計(jì)模式的妙處,但是設(shè)計(jì)模式在平時(shí)工作中用得較少,一段時(shí)間后再來回憶看過的這些東西,基本上只能記住它們的名字,其他的都想不起來。所以準(zhǔn)備再統(tǒng)一復(fù)習(xí)一遍常用的設(shè)計(jì)模式,順便寫點(diǎn)自己理解的東西,當(dāng)做筆記吧,希望以后想不起來時(shí)再回來看能夠迅速的想起。
正式開始
??言歸正傳,《Head First設(shè)計(jì)模式》這本書講了23種設(shè)計(jì)模式,網(wǎng)上大致將這23種模式分為三類,分別為:
- 創(chuàng)建型模式:指的是用來創(chuàng)建對(duì)象以便能從系統(tǒng)中解耦。
有工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。 - 結(jié)構(gòu)型模式:指的是通過各個(gè)對(duì)象來組成大規(guī)模的對(duì)象結(jié)構(gòu)。
有適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。 - 行為型模式:指的是用來在對(duì)象之間管理算法、關(guān)系等。
有策略模式、模板方法模式、觀察者模式、迭代子模式、責(zé)任鏈模式、命令模式、備忘錄模式、狀態(tài)模式、訪問者模式、中介者模式、解釋器模式。
創(chuàng)建者模式
0.簡(jiǎn)單工廠模式
??簡(jiǎn)單工廠模式其實(shí)不算在23種設(shè)計(jì)模式中,但在平時(shí)開發(fā)中用的場(chǎng)景還是比較多的,而且和工廠方法模式、抽象工廠模式類似,所以還是先看下簡(jiǎn)單工廠模式。
??簡(jiǎn)單工廠模式有一個(gè)工廠、一類產(chǎn)品,外部調(diào)用并不關(guān)心產(chǎn)品是怎么創(chuàng)建的,它只需要告訴這個(gè)工廠,我需要什么類型的產(chǎn)品即可,具體創(chuàng)建邏輯由工廠內(nèi)部處理。工廠會(huì)根據(jù)調(diào)用者傳給它的類型進(jìn)行產(chǎn)品的創(chuàng)建,關(guān)系圖如下:
圖1
舉個(gè)栗子,經(jīng)典的汽車生產(chǎn):
首先,創(chuàng)建汽車基類:
@interface Car : NSObject
- (void)carInfomation;
@end
然后創(chuàng)建它的具體實(shí)現(xiàn)類:
@interface AudiCar : Car
@end
@implementation AudiCar
- (void)carInfomation {
NSLog(@"I am AudiCar");
}
@end
@interface BenzCar : Car
@end
@implementation BenzCar
- (void)carInfomation {
NSLog(@"I am BenzCar");
}
@end
最后創(chuàng)建工廠:
@implementation CarsFactory
+ (Car *)createCarWithType:(CarType)carType {
Car *car;
switch (carType) {
case CarTypeAudi:
car = [[AudiCar alloc] init];
break;
case CarTypeBenz:
car = [[BenzCar alloc] init];
break;
}
return car;
}
@end
外部調(diào)用者只需給工廠提供參數(shù)即可:
- (void)testSimpleFactory {
// Audi
Car *audi = [CarsFactory createCarWithType:CarTypeAudi];
[audi carInfomation];
// Benz
Car *benz = [CarsFactory createCarWithType:CarTypeBenz];
[benz carInfomation];
}
測(cè)試結(jié)果:
2018-01-03 21:39:41.834124+0800 DesignPatternDemo[1582:77442] I am AudiCar
2018-01-03 21:39:41.834264+0800 DesignPatternDemo[1582:77442] I am BenzCar
總結(jié)
??簡(jiǎn)單工廠模式可以將同一類型產(chǎn)品創(chuàng)建集中到工廠里,使用者無需知道產(chǎn)品的內(nèi)部創(chuàng)建邏輯,只需提供產(chǎn)品的類型,工廠就可以創(chuàng)建出相應(yīng)的產(chǎn)品。
??雖然簡(jiǎn)單工廠模式可以實(shí)現(xiàn)調(diào)用者跟產(chǎn)品之間的解耦,但是并不符合開閉原則,即產(chǎn)品的創(chuàng)建依賴于工廠類,每次添加一款新產(chǎn)品就得修改工廠內(nèi)部的實(shí)現(xiàn),產(chǎn)品越多switch(或者if-else)就越長(zhǎng)。因此就有了工廠方法模式。
1.工廠方法模式
??工廠方法模式是創(chuàng)建一個(gè)工廠基類以及若干個(gè)具體工廠類,每個(gè)工廠只負(fù)責(zé)自己這款產(chǎn)品的創(chuàng)建,即每款產(chǎn)品有自己對(duì)應(yīng)的一個(gè)工廠。這樣如果新加一款產(chǎn)品不需要去修改之前工廠實(shí)現(xiàn),只需再實(shí)現(xiàn)一個(gè)創(chuàng)建新產(chǎn)品的工廠。具體關(guān)系如下:
關(guān)系圖2.
還是那個(gè)栗子:
汽車的結(jié)構(gòu)不變,修改工廠的實(shí)現(xiàn),首先創(chuàng)建一個(gè)工廠基類:
@interface CarBaseFactory : NSObject
+ (Car *)createCar;
@end
然后實(shí)現(xiàn)創(chuàng)建具體汽車的具體工廠:
@interface AudiCarFactory : CarBaseFactory
@end
@implementation AudiCarFactory
+ (Car *)createCar {
AudiCar *car = [[AudiCar alloc] init];
return car;
}
@end
@interface BenzCarFactory : CarBaseFactory
@end
@implementation BenzCarFactory
+ (Car *)createCar {
BenzCar *car = [[BenzCar alloc] init];
return car;
}
@end
外部調(diào)用者:
- (void)testFactoryMethod {
// Audi
Car *audi = [AudiCarFactory createCar];
[audi carInfomation];
// Benz
Car *benz = [BenzCarFactory createCar];
[benz carInfomation];
}
此時(shí)如果需要再加新的產(chǎn)品,就不需要再去改之前的代碼,只需添加新的產(chǎn)品和創(chuàng)建該產(chǎn)品的工廠,代碼如下:
新的汽車保時(shí)捷:
@interface PorscheCar : Car
@end
@implementation PorscheCar
- (void)carInfomation {
NSLog(@"I am PorscheCar");
}
@end
保時(shí)捷汽車工廠:
@interface PorscheCarFactory : CarBaseFactory
@end
@implementation PorscheCarFactory
+ (Car *)createCar {
PorscheCar *car = [[PorscheCar alloc] init];
return car;
}
@end
外部調(diào)用者:
- (void)testFactoryMethod {
// Audi
Car *audi = [AudiCarFactory createCar];
[audi carInfomation];
// Benz
Car *benz = [BenzCarFactory createCar];
[benz carInfomation];
// Porsche
Car *porsche = [PorscheCarFactory createCar];
[porsche carInfomation];
}
測(cè)試結(jié)果:
2018-01-03 22:11:46.448233+0800 DesignPatternDemo[1794:108045] I am AudiCar
2018-01-03 22:11:46.448372+0800 DesignPatternDemo[1794:108045] I am BenzCar
2018-01-03 22:11:46.448465+0800 DesignPatternDemo[1794:108045] I am PorscheCar
總結(jié)
??工廠方法模式通過每個(gè)工廠只負(fù)責(zé)一款產(chǎn)品的創(chuàng)建來解決簡(jiǎn)單工廠模式不符合開閉原則的缺點(diǎn),但也帶來了類文件過多的缺點(diǎn)(大多數(shù)設(shè)計(jì)模式都會(huì)有這個(gè)缺點(diǎn)),很多時(shí)候這些類文件都只實(shí)現(xiàn)很簡(jiǎn)單的功能。
3.抽象工廠模式
??抽象工廠模式是工廠方法模式的升級(jí)版,或者說工廠方法模式是抽象工廠模式的特例。在工廠方法模式中一個(gè)工廠只能創(chuàng)建一款產(chǎn)品,而在抽象工廠模式中一個(gè)工廠可以創(chuàng)建一個(gè)產(chǎn)品簇(即一個(gè)產(chǎn)品和這個(gè)產(chǎn)品的許多線下產(chǎn)品)。關(guān)系圖如下:
關(guān)系圖3.
還是那個(gè)栗子,各種不同的汽車可能對(duì)應(yīng)著不同的配件,比如Audi配置著發(fā)動(dòng)機(jī)A、空調(diào)A,Benz配置著發(fā)動(dòng)機(jī)B、空調(diào)B。
首先定義發(fā)動(dòng)機(jī):
@interface Engine : NSObject
- (void)engineInfomation;
@end
@interface EngineA : Engine
@end
@implementation EngineA
- (void)engineInfomation {
NSLog(@"I am EngineA");
}
@end
@interface EngineB : Engine
@end
@implementation EngineB
- (void)engineInfomation {
NSLog(@"I am EngineB");
}
@end
定義空調(diào):
@interface AirConditioner : NSObject
- (void)airConditionerInfomation;
@end
@interface AirConditionerA : AirConditioner
@end
@implementation AirConditionerA
- (void)airConditionerInfomation {
NSLog(@"I am AirConditionerA");
}
@end
@interface AirConditionerB : AirConditioner
@end
@implementation AirConditionerB
- (void)airConditionerInfomation {
NSLog(@"I am AirConditionerB");
}
@end
修改汽車類,添加發(fā)動(dòng)機(jī)和空調(diào)屬性:
@interface Car : NSObject
@property (nonatomic, strong) Engine *engine;
@property (nonatomic, strong) AirConditioner *airConditioner;
- (void)carInfomation;
@end
為工廠類添加創(chuàng)建發(fā)動(dòng)機(jī)和空調(diào)的方法:
@interface CarBaseFactory : NSObject
+ (Car *)createCar;
+ (Engine *)createEngine;
+ (AirConditioner *)createAirConditioner;
@end
@implementation AudiCarFactory
+ (Car *)createCar {
AudiCar *car = [[AudiCar alloc] init];
return car;
}
+ (Engine *)createEngine {
EngineA *engine = [[EngineA alloc] init];
return engine;
}
+ (AirConditioner *)createAirConditioner {
AirConditionerA *airConditioner = [[AirConditionerA alloc] init];
return airConditioner;
}
@end
@implementation BenzCarFactory
+ (Car *)createCar {
BenzCar *car = [[BenzCar alloc] init];
return car;
}
+ (Engine *)createEngine {
EngineB *engine = [[EngineB alloc] init];
return engine;
}
+ (AirConditioner *)createAirConditioner {
AirConditionerB *airConditioner = [[AirConditionerB alloc] init];
return airConditioner;
}
@end
外部調(diào)用者調(diào)用:
- (void)testAbstractFactory {
// Audi
Car *audi = [AudiCarFactory createCar];
audi.engine = [AudiCarFactory createEngine];
audi.airConditioner = [AudiCarFactory createAirConditioner];
[audi carInfomation];
[audi.engine engineInfomation];
[audi.airConditioner airConditionerInfomation];
// Benz
Car *benz = [BenzCarFactory createCar];
benz.engine = [BenzCarFactory createEngine];
benz.airConditioner = [BenzCarFactory createAirConditioner];
[benz carInfomation];
[benz.engine engineInfomation];
[benz.airConditioner airConditionerInfomation];
}
測(cè)試結(jié)果:
2018-01-03 22:42:55.410243+0800 DesignPatternDemo[1958:151756] I am AudiCar
2018-01-03 22:42:55.410380+0800 DesignPatternDemo[1958:151756] I am EngineA
2018-01-03 22:42:55.410488+0800 DesignPatternDemo[1958:151756] I am AirConditionerA
2018-01-03 22:42:55.410605+0800 DesignPatternDemo[1958:151756] I am BenzCar
2018-01-03 22:42:55.410703+0800 DesignPatternDemo[1958:151756] I am EngineB
2018-01-03 22:42:55.410976+0800 DesignPatternDemo[1958:151756] I am AirConditionerB
總結(jié)
??工廠方法模式只有一個(gè)抽象產(chǎn)品類,而抽象工廠模式有多個(gè)。工廠方法模式的具體工廠類只能創(chuàng)建一個(gè)具體產(chǎn)品類的實(shí)例,而抽象工廠模式可以創(chuàng)建多個(gè)??梢赃@么理解,抽象工廠就像一家完整的工廠,可以創(chuàng)建工廠里的各種產(chǎn)品,而工廠方法就像工廠里的一條產(chǎn)品線,只負(fù)責(zé)生產(chǎn)一款產(chǎn)品。
4.單例模式
??單例模式在iOS開發(fā)中相當(dāng)重要,也相當(dāng)常見。單例模式保證了在程序運(yùn)行期間該對(duì)象只有一個(gè)實(shí)例。
示例代碼:
@implementation CarPerformanceCenter
+ (instancetype)shareInstance {
static CarPerformanceCenter *center;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
center = [[CarPerformanceCenter alloc] init];
});
return center;
}
@end
5.建造者模式、原型模式
??這兩種設(shè)計(jì)模式平時(shí)用得較少,暫時(shí)不討論,后面有時(shí)間再繼續(xù)研究。