iOS設(shè)計模式-工廠方法與抽象工廠

1. 什么是工廠模式

工廠模式(Factory pattern)在設(shè)計模式中屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式。在工廠模式中,我們在創(chuàng)建對象時不會對客戶端暴露創(chuàng)建邏輯,并且是通過使用一個共同的接口來指向新創(chuàng)建的對象

2. 工廠模式分類

工廠模式一般可以分為三類:

  • 簡單工廠模式(Simple Factory Pattern)
  • 工廠方法模式(Factory Method Pattern)
  • 抽象工廠模式(Abstract Factory Pattern)

接下來我們分別對這三個模式進(jìn)行說明。

2.1 簡單工廠模式

簡單工廠模式又稱作靜態(tài)工廠方法模式,簡單工廠模式專門定義一個工廠類來負(fù)責(zé)創(chuàng)建其他類的實例,且被創(chuàng)建的實例通常都具有共同的父類。它雖然不屬于設(shè)計模式中的一種,但是在應(yīng)用中依然很常見。

2.1.1 主要角色與關(guān)系

主要由三個角色組成:

  • 工廠類(Factory):簡單工廠模式的核心,它負(fù)責(zé)實現(xiàn)創(chuàng)建所有實例的內(nèi)部邏輯。工廠類的創(chuàng)建產(chǎn)品類的方法可以被外界直接調(diào)用,創(chuàng)建所需的產(chǎn)品對象。
  • 抽象產(chǎn)品類(AbstractProduct):簡單工廠模式所創(chuàng)建的所有對象的父類,它負(fù)責(zé)描述所有實例所共有的公共接口。
  • 具體產(chǎn)品類(Product):是簡單工廠模式的創(chuàng)建實體類。


    圖片.png
2.1.2 代碼實現(xiàn)

我們以生產(chǎn)電腦為例,假設(shè)有一個代工廠,它既可以生產(chǎn)蘋果電腦,也可以生產(chǎn)小米電腦,這時候如果需要生產(chǎn)其中任意一種電腦,就直接找代工廠就行了。

  1. 創(chuàng)建一個產(chǎn)品抽象類Computer,定義好基礎(chǔ)方法

// Computer.h

#import <Foundation/Foundation.h>

@interface Computer : NSObject
- (NSString *)productName;
@end


// Computer.m

#import "Computer.h"

@implementation Computer
- (NSString *)productName {
    NSAssert(false, @"must implement in subClass");
    return nil;
}
@end
  1. 創(chuàng)建產(chǎn)品具體類
    2.1 mac電腦類

// Mac.h
#import "Computer.h"

@interface Mac : Computer

@end


// Mac.m

#import "Mac.h"

@implementation Mac

- (NSString *)productName {
    return @"Mac";
}

@end

2.2 創(chuàng)建小米電腦類


// XiaoMi.h

#import "Computer.h"

@interface XiaoMi : Computer

@end


// XiaoMi.m

#import "XiaoMi.h"

@implementation XiaoMi

- (NSString *)productName {
    return @"XiaoMi";
}

@end
  1. 產(chǎn)品都已經(jīng)定義好了,接下來我們需要定義一個工廠類,裝門從事生產(chǎn)這些商品

// ComputerSimpleFactory.h
#import <Foundation/Foundation.h>
#import "Mac.h"
#import "XiaoMi.h"

@interface ComputerSimpleFactory : NSObject

+ (Computer *)createComputerWithType:(NSInteger)type;

@end


// ComputerSimpleFactory.m

#import "ComputerSimpleFactory.h"

@implementation ComputerSimpleFactory

+ (Computer *)createComputerWithType:(NSInteger)type {
    switch (type) {
        case 1: {
            //do something for create
            Mac *computer = [[Mac alloc] init];
            return computer;
        }
            break;
        case 2: {
            //do something for create
            XiaoMi *computer = [[XiaoMi alloc] init];
            return computer;
        }
        default:
            break;
    }
    return nil;
}

@end
  1. 調(diào)用測試
+ (void)test1 {
    Computer *macComputer = [ComputerSimpleFactory createComputerWithType:1];
    NSLog(@"computer name = %@", macComputer.productName);
    Computer *xmComputer = [ComputerSimpleFactory createComputerWithType:2];
    NSLog(@"computer name = %@", xmComputer.productName);
}
2.1.3 分析
  • 可以看出通過工廠類對產(chǎn)品創(chuàng)建進(jìn)行了封裝,使調(diào)用者不需要知道創(chuàng)建的具體邏輯,只需要調(diào)用工廠方法,即可得到相應(yīng)的實例。一旦產(chǎn)品創(chuàng)建邏輯需要修改,也只需要修改工廠類即可,不必全局修改創(chuàng)建邏輯。
  • 系統(tǒng)擴展困難,一旦添加新產(chǎn)品就不得不修改工廠類創(chuàng)建方法邏輯,破壞了“開閉原則”。在產(chǎn)品類型較多時,有可能造成工廠邏輯過于復(fù)雜,不利于系統(tǒng)的擴展和維護。
2.1.4 適用范圍
  • 適用于一些創(chuàng)建實例邏輯較為復(fù)雜,創(chuàng)建類型固定且被創(chuàng)建的類一般屬于同一父類的情況。

2.2 工廠方法模式

工廠方法模式,又稱工廠模式、多態(tài)工廠模式和虛擬構(gòu)造器模式。

Define an interface for creating an object,but let subclasses decide which class toinstantiate.Factory Method lets a class defer instantiation to subclasses.

定義一個用于創(chuàng)建對象的接口,讓子類決定實例化哪一個類。工廠方法使一個類的實例化延遲到其子類。
這滿足創(chuàng)建型模式中所要求的“創(chuàng)建與使用相分離”的特點。同時改進(jìn)了簡單工廠模式中不易拓展的問題。

2.2.1 主要角色與關(guān)系

主要角色組成:

  • 抽象工廠(AbstractFactory):提供了創(chuàng)建產(chǎn)品的接口,調(diào)用者通過它訪問具體工廠的工廠方法來創(chuàng)建產(chǎn)品。
  • 具體工廠(ConcreteFactory):主要是實現(xiàn)抽象工廠中的抽象方法,完成具體產(chǎn)品的創(chuàng)建。
  • 抽象產(chǎn)品(AbstractProduct):定義了產(chǎn)品的規(guī)范,描述了產(chǎn)品的主要特性和功能。
  • 具體產(chǎn)品(Product):實現(xiàn)了抽象產(chǎn)品角色所定義的接口,由具體工廠來創(chuàng)建,它同具體工廠之間一一對應(yīng)。


    圖片.png
2.2.2 代碼實現(xiàn)

我們依然以生產(chǎn)電腦為例,為了保持生產(chǎn)質(zhì)量,一個工廠我們只讓他負(fù)責(zé)生產(chǎn)一種電腦,蘋果電腦生產(chǎn)就交給蘋果電腦工廠,小米電腦生產(chǎn)就交給小米電腦工廠。

  1. 創(chuàng)建和定義抽象產(chǎn)品Computer和具體產(chǎn)品Mac、XiaoMi。這里產(chǎn)品類和前面一致,不再重復(fù)闡述。
  2. 定義工廠抽象類ComputerMethodFactory

// ComputerMethodFactory.h

#import <Foundation/Foundation.h>
#import "Computer.h"

@interface ComputerMethodFactory : NSObject
+ (Computer *)createComputer;
@end


// ComputerMethodFactory.m

#import "ComputerMethodFactory.h"

@implementation ComputerMethodFactory

+ (Computer *)createComputer {
    NSAssert(false, @"must implement ins subClass");
    return nil;
}

@end
  1. 定義具體工廠類
    定義蘋果電腦工廠類 MacComputerFactory
    定義小米電腦工廠類 XiaoMiComputerFactory
// MacComputerFactory.h

#import "ComputerMethodFactory.h"

@interface MacComputerFactory : ComputerMethodFactory

@end


// MacComputerFactory.h

#import "MacComputerFactory.h"
#import "Mac.h"

@implementation MacComputerFactory

+ (Computer *)createComputer {
    //do something for create
    Mac *macComputer = [[Mac alloc] init];
    return macComputer;
}

@end
// XiaoMiComputerFactory.h

#import "ComputerMethodFactory.h"

@interface XiaoMiComputerFactory : ComputerMethodFactory

@end


// XiaoMiComputerFactory.m

#import "XiaoMiComputerFactory.h"
#import "XiaoMi.h"

@implementation XiaoMiComputerFactory

+ (Computer *)createComputer {
    //do something for create
    XiaoMi *xmComputer = [[XiaoMi alloc] init];
    return xmComputer;
}

@end
  1. 接下來進(jìn)行簡單的調(diào)用測試
//工廠方法模式測試
+ (void)test2 {
    Computer *macComputer = [MacComputerFactory createComputer];
    NSLog(@"computer name = %@", macComputer.productName);
    Computer *xmComputer = [XiaoMiComputerFactory createComputer];
    NSLog(@"computer name = %@", xmComputer.productName);
}
2.2.3 分析
  • 用戶只需要知道具體工廠的名稱就可得到所要的產(chǎn)品,無須知道產(chǎn)品的具體創(chuàng)建過程;
  • 在系統(tǒng)增加新的產(chǎn)品時只需要添加具體產(chǎn)品類和對應(yīng)的具體工廠類,無須對原工廠進(jìn)行任何修改,滿足開閉原則;
  • 高層模塊值需要知道產(chǎn)品的抽象類,其他的實現(xiàn)類都不用關(guān)心,符合迪米特法則,我不需要的就不要去交流;也符合依賴倒置原則,只依賴產(chǎn)品類的抽象;當(dāng)然也符合里氏替換原則.
  • 每增加一個產(chǎn)品就要增加一個具體產(chǎn)品類和一個對應(yīng)的具體工廠類,這增加了系統(tǒng)的復(fù)雜度
2.2.4 適用范圍
  • 工廠方法模式在所有需要生成對象的地方都可以使用,但是需要慎重地考慮是否要增加一個工廠類進(jìn)行管理,增加代碼的復(fù)雜度。
  • 需要靈活的、可擴展的框架時,可以考慮采用工廠方法模式,如:產(chǎn)品種類未來仍然可能保持新增的情況

2.3 抽象工廠模式

抽象工廠模式

Provide an interface for creating families of related or dependent objects withoutspecifying their concrete classes

為創(chuàng)建一組相關(guān)或相互依賴的對象提供一個接口,而且無須指定它們的具體類
抽象工廠模式是工廠方法模式的升級版本,工廠方法模式只生產(chǎn)一個等級的產(chǎn)品,而抽象工廠模式可生產(chǎn)多個等級的產(chǎn)品,可以生產(chǎn)一個產(chǎn)品族的產(chǎn)品。

2.3.1 主要角色與關(guān)系

主要由以下角色組成:

  • 抽象工廠(Abstract Factory):提供了創(chuàng)建產(chǎn)品的接口,它包含多個創(chuàng)建產(chǎn)品的方法 newProduct(),可以創(chuàng)建多個不同等級的產(chǎn)品。
  • 具體工廠(Concrete Factory):主要是實現(xiàn)抽象工廠中的多個抽象方法,完成具體產(chǎn)品的創(chuàng)建。
  • 抽象產(chǎn)品(Product):定義了產(chǎn)品的規(guī)范,描述了產(chǎn)品的主要特性和功能,抽象工廠模式有多個抽象產(chǎn)品。
  • 具體產(chǎn)品(ConcreteProduct):實現(xiàn)了抽象產(chǎn)品角色所定義的接口,由具體工廠來創(chuàng)建,它 同具體工廠之間是多對一的關(guān)系。


    圖片.png
2.3.2 代碼實現(xiàn)

我們以前面工廠方法的例子的基礎(chǔ)上進(jìn)行舉例說明。現(xiàn)在我們希望工廠在原來生產(chǎn)電腦的基礎(chǔ)上,同時支持生產(chǎn)手機。這個時候我們就需要首先先取得生產(chǎn)許可(在抽象工廠類上賦予生產(chǎn)電腦和手機的能力),然后在具體工廠類進(jìn)行生產(chǎn),蘋果工廠類負(fù)責(zé)生產(chǎn)蘋果手機和蘋果電腦,小米工廠則負(fù)責(zé)生產(chǎn)小米手機和小米電腦。

  1. 創(chuàng)建和定義抽象產(chǎn)品Computer和具體產(chǎn)品Mac、XiaoMi。這里產(chǎn)品類和前面一致,不再重復(fù)闡述。
  2. 創(chuàng)建和定義新的抽象產(chǎn)品Phone和具體產(chǎn)品類iPhone 和XiaoMiPhone

// Phone.h
#import <Foundation/Foundation.h>

@interface Phone : NSObject

- (NSString *)productName;

@end


// phone.m
#import "Phone.h"

@implementation Phone

- (NSString *)productName {
    NSAssert(false, @"must implement in subClass");
    return nil;
}
@end

// iPhone.m
#import "Phone.h"

@interface iPhone : Phone

@end


// iPhone.m
#import "iPhone.h"

@implementation iPhone

- (NSString *)productName {
    return @"iphone";
}

@end
// XiaoMiPhone.h
#import "Phone.h"

@interface XiaoMiPhone : Phone

@end


// XiaoMiPhone.m
#import "XiaoMiPhone.h"

@implementation XiaoMiPhone
- (NSString *)productName {
    return @"XiaoMiPhone";
}
@end
  1. 創(chuàng)建和定義抽象工廠類 ElectronAbstractFactory,定義生產(chǎn)手機和電腦功能
// ElectronAbstractFactory
#import <Foundation/Foundation.h>
#import "Phone.h"
#import "Computer.h"

@protocol ElectronAbstractFactoryInterface <NSObject>
@required
+ (Phone *)createPhone;
+ (Computer *)createComputer;
@end

@interface ElectronAbstractFactory : NSObject<ElectronAbstractFactoryInterface>

@end


// ElectronAbstractFactory.m
#import "ElectronAbstractFactory.h"

@implementation ElectronAbstractFactory

+ (Phone *)createPhone {
    NSAssert(false, @"must implement in subClass");
    return nil;
}

+ (Computer *)createComputer {
    NSAssert(false, @"must implement in subClass");
    return nil;
}

@end
  1. 定義具體工廠類AppleElectronFactory和XiaoMiElectronFactory
// AppleElectronFactory.h
#import "ElectronAbstractFactory.h"

@interface AppleElectronFactory : ElectronAbstractFactory

@end


// AppleElectronFactory.m
#import "AppleElectronFactory.h"
#import "iPhone.h"
#import "Mac.h"

@implementation AppleElectronFactory

+ (Computer *)createComputer {
    //do something for create
    Mac *mac = [[Mac alloc] init];
    return mac;
}

+ (Phone *)createPhone {
     //do something for create
    iPhone *iphone = [[iPhone alloc] init];
    return iphone;
}

@end
// XiaoMiElectronFactory.h
#import "ElectronAbstractFactory.h"

@interface XiaoMiElectronFactory : ElectronAbstractFactory

@end


// XiaoMiElectronFactory.m
#import "XiaoMiElectronFactory.h"
#import "XiaoMiPhone.h"
#import "XiaoMi.h"

@implementation XiaoMiElectronFactory

+ (Computer *)createComputer {
    //do something for create
    XiaoMi *mac = [[XiaoMi alloc] init];
    return mac;
}

+ (Phone *)createPhone {
     //do something for create
    XiaoMiPhone *iphone = [[XiaoMiPhone alloc] init];
    return iphone;
}

@end
  1. 進(jìn)行調(diào)用測試對應(yīng)代碼
+ (void)test3 {
    Computer *macComputer = [AppleElectronFactory createComputer];
    NSLog(@"computer name = %@", macComputer.productName);
    Phone *iphone = [AppleElectronFactory createPhone];
    NSLog(@"computer name = %@", [iphone productName]);
    Computer *xmComputer = [XiaoMiComputerFactory createComputer];
    NSLog(@"computer name = %@", xmComputer.productName);
    Phone *xiaomiPhone = [XiaoMiElectronFactory createPhone];
    NSLog(@"computer name = %@", [xiaomiPhone productName]);
}
2.3.3 分析
  • 抽象工廠模式除了具有工廠方法模式的優(yōu)點外,可以在類的內(nèi)部對產(chǎn)品族中相關(guān)聯(lián)的多等級產(chǎn)品共同管理,而不必專門引入多個新的類來進(jìn)行管理
  • 當(dāng)增加一個新的產(chǎn)品族時不需要修改原代碼,滿足開閉原則
  • 但是當(dāng)產(chǎn)品族中需要增加一個新的產(chǎn)品時,所有的工廠類都需要進(jìn)行修改又與開閉原則相悖
2.3.4 適用范圍
  • 當(dāng)要被創(chuàng)建的對象是一系列具有相互關(guān)聯(lián)、相互依賴的產(chǎn)品類時
  • 系統(tǒng)中有多個產(chǎn)品族,但是每次只會適用其中一個產(chǎn)品族的產(chǎn)品
  • 涉及不同運行環(huán)境的時候,都可以考慮使用抽象工廠模式。例如一個應(yīng)用,需要在三個不同平臺(Windows、Linux、Android 通過抽象工廠模式屏蔽掉操作系統(tǒng)對應(yīng)用的影響。三個不同操作系統(tǒng)上的軟件功能、應(yīng)用邏輯、UI都應(yīng)該是非常類似的,唯一不同的是調(diào)用不同的工廠方法,由不同的產(chǎn)品類去處理與操作系統(tǒng)交互的信息
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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