設(shè)計(jì)模式之創(chuàng)建型模式

前言

??前段時(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ù)研究。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容