設計模式之建立型模式
前言
前段時間看了《Head First設計模式》這本書,雖然沒有看完,但常用的設計模式基本都看了一遍。剛開始看完基本都能理解,也能體會到設計模式的妙處,但是設計模式在平時工作中用得較少,一段時間後再來回憶看過的這些東西,基本上只能記住它們的名字,其他的都想不起來。所以準備再統一複習一遍常用的設計模式,順便寫點自己理解的東西,當做筆記吧,希望以後想不起來時再回來看能夠迅速的想起。
正式開始
言歸正傳,《Head First設計模式》這本書講了23種設計模式,網上大致將這23種模式分為三類,分別為:
- 建立型模式:指的是用來建立物件以便能從系統中解耦。
有工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。 - 結構型模式:指的是通過各個物件來組成大規模的物件結構。
有介面卡模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。 - 行為型模式:指的是用來在物件之間管理演算法、關係等。
有策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、直譯器模式。
建立者模式
0.簡單工廠模式
簡單工廠模式其實不算在23種設計模式中,但在平時開發中用的場景還是比較多的,而且和工廠方法模式、抽象工廠模式類似,所以還是先看下簡單工廠模式。
簡單工廠模式有一個工廠、一類產品,外部呼叫並不關心產品是怎麼建立的,它只需要告訴這個工廠,我需要什麼型別的產品即可,具體建立邏輯由工廠內部處理。工廠會根據呼叫者傳給它的型別進行產品的建立,關係圖如下:
圖1
舉個栗子,經典的汽車生產:
首先,建立汽車基類:
@interface Car : NSObject
- (void)carInfomation;
@end
然後建立它的具體實現類:
@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
最後建立工廠:
@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
外部呼叫者只需給工廠提供引數即可:
- (void)testSimpleFactory {
// Audi
Car *audi = [CarsFactory createCarWithType:CarTypeAudi];
[audi carInfomation];
// Benz
Car *benz = [CarsFactory createCarWithType:CarTypeBenz];
[benz carInfomation];
}
測試結果:
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
總結
簡單工廠模式可以將同一型別產品建立集中到工廠裡,使用者無需知道產品的內部建立邏輯,只需提供產品的型別,工廠就可以建立出相應的產品。
雖然簡單工廠模式可以實現呼叫者跟產品之間的解耦,但是並不符合開閉原則,即產品的建立依賴於工廠類,每次新增一款新產品就得修改工廠內部的實現,產品越多switch(或者if-else)就越長。因此就有了工廠方法模式。
1.工廠方法模式
工廠方法模式是建立一個工廠基類以及若干個具體工廠類,每個工廠只負責自己這款產品的建立,即每款產品有自己對應的一個工廠。這樣如果新加一款產品不需要去修改之前工廠實現,只需再實現一個建立新產品的工廠。具體關係如下:
關係圖2.
還是那個栗子:
汽車的結構不變,修改工廠的實現,首先建立一個工廠基類:
@interface CarBaseFactory : NSObject
+ (Car *)createCar;
@end
然後實現建立具體汽車的具體工廠:
@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
外部呼叫者:
- (void)testFactoryMethod {
// Audi
Car *audi = [AudiCarFactory createCar];
[audi carInfomation];
// Benz
Car *benz = [BenzCarFactory createCar];
[benz carInfomation];
}
此時如果需要再加新的產品,就不需要再去改之前的程式碼,只需新增新的產品和建立該產品的工廠,程式碼如下:
新的汽車保時捷:
@interface PorscheCar : Car
@end
@implementation PorscheCar
- (void)carInfomation {
NSLog(@"I am PorscheCar");
}
@end
保時捷汽車工廠:
@interface PorscheCarFactory : CarBaseFactory
@end
@implementation PorscheCarFactory
+ (Car *)createCar {
PorscheCar *car = [[PorscheCar alloc] init];
return car;
}
@end
外部呼叫者:
- (void)testFactoryMethod {
// Audi
Car *audi = [AudiCarFactory createCar];
[audi carInfomation];
// Benz
Car *benz = [BenzCarFactory createCar];
[benz carInfomation];
// Porsche
Car *porsche = [PorscheCarFactory createCar];
[porsche carInfomation];
}
測試結果:
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
總結
工廠方法模式通過每個工廠只負責一款產品的建立來解決簡單工廠模式不符合開閉原則的缺點,但也帶來了類檔案過多的缺點(大多數設計模式都會有這個缺點),很多時候這些類檔案都只實現很簡單的功能。
3.抽象工廠模式
抽象工廠模式是工廠方法模式的升級版,或者說工廠方法模式是抽象工廠模式的特例。在工廠方法模式中一個工廠只能建立一款產品,而在抽象工廠模式中一個工廠可以建立一個產品簇(即一個產品和這個產品的許多線下產品)。關係圖如下:
關係圖3.
還是那個栗子,各種不同的汽車可能對應著不同的配件,比如Audi配置著發動機A、空調A,Benz配置著發動機B、空調B。
首先定義發動機:
@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
定義空調:
@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
修改汽車類,新增發動機和空調屬性:
@interface Car : NSObject
@property (nonatomic, strong) Engine *engine;
@property (nonatomic, strong) AirConditioner *airConditioner;
- (void)carInfomation;
@end
為工廠類新增建立發動機和空調的方法:
@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
外部呼叫者呼叫:
- (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];
}
測試結果:
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
總結
工廠方法模式只有一個抽象產品類,而抽象工廠模式有多個。工廠方法模式的具體工廠類只能建立一個具體產品類的例項,而抽象工廠模式可以建立多個。可以這麼理解,抽象工廠就像一家完整的工廠,可以建立工廠裡的各種產品,而工廠方法就像工廠裡的一條產品線,只負責生產一款產品。
4.單例模式
單例模式在iOS開發中相當重要,也相當常見。單例模式保證了在程式執行期間該物件只有一個例項。
示例程式碼:
@implementation CarPerformanceCenter
+ (instancetype)shareInstance {
static CarPerformanceCenter *center;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
center = [[CarPerformanceCenter alloc] init];
});
return center;
}
@end
5.建造者模式、原型模式
這兩種設計模式平時用得較少,暫時不討論,後面有時間再繼續研究。
相關文章
- JavaScript設計模式之建立型設計模式JavaScript設計模式
- 設計模式(一)建立型之單例模式設計模式單例
- PHP設計模式—建立型設計模式PHP設計模式
- 設計模式-建立型設計模式
- 設計模式-建立型-單例模式設計模式單例
- (Java)設計模式:建立型Java設計模式
- 建立型設計模式——抽象工廠模式設計模式抽象
- 設計模式--建造者模式Builder(建立型)設計模式UI
- 設計模式--工廠模式Factory(建立型)設計模式
- 設計模式--原型模式Prototype(建立型)設計模式原型
- 聊一聊設計模式(二)-- 建立型設計模式設計模式
- C++設計模式建立型工廠模式C++設計模式
- 設計模式--單件模式Singleton(建立型)設計模式
- 建立型設計模式對比總結 設計模式(八)設計模式
- JavaScript設計模式之結構型設計模式JavaScript設計模式
- 設計模式之代理模式(結構型)設計模式
- JAVA設計模式 4【建立型】理解建造者模式Java設計模式
- 設計模式(三)----建立型模式之單例模式(一)設計模式單例
- Typescript玩轉設計模式 之 建立型模式TypeScript設計模式
- 大話 PHP 設計模式--建立型PHP設計模式
- 物件導向-設計模式-建立型物件設計模式
- 設計模式-建立型-工廠方法設計模式
- JAVA設計模式 3【建立型】理解工廠模式與抽象工廠模式Java設計模式抽象
- 【Java】設計模式--建立型模式Java設計模式
- python--設計模式--4--建立型--工廠方法模式Python設計模式
- Golang 常用的五種建立型設計模式Golang設計模式
- 工廠方法模式GoF23種設計模式之建立型模式之工廠方法模式Go設計模式
- 解說21種設計模式之第一篇_原型模式(物件建立型)設計模式原型物件
- Java設計模式——單例模式(建立型模式)Java設計模式單例
- 【設計模式(四)】建立型模式--原型模式設計模式原型
- 設計模式-建立型模式學習設計模式
- JAVA設計模式一 建立型模式Java設計模式
- 設計模式之Plugin模式設計模式Plugin
- 設計模式之策略模式設計模式
- 《設計模式》之代理模式設計模式
- 設計模式之【策略模式】設計模式
- 【設計模式之代理模式】設計模式
- 【設計模式之策略模式】設計模式