工廠模式

GOF是這樣描述工廠模式的:

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

  1. 簡(jiǎn)單工廠模式(Simple Factory)
  2. 工廠方法模式(Factory Method)
  3. 抽象工廠模式(Abstract Factory)

簡(jiǎn)單工廠模式

簡(jiǎn)單工廠使用場(chǎng)景

  1. 簡(jiǎn)化生產(chǎn)流程
  2. 隔離生產(chǎn)產(chǎn)品的細(xì)節(jié)
  3. 不同類型的產(chǎn)品之間有著一些共同的功能
  4. 一個(gè)具體的工廠

抽象工廠模式

工廠方法把生產(chǎn)產(chǎn)品的方式封裝起來了,但是一個(gè)工廠只能生產(chǎn)一類對(duì)象,當(dāng)一個(gè)工廠需要生產(chǎn)多類產(chǎn)品的時(shí)候,就需要使用抽象工廠了。抽象工廠(AbstractFactory)類定義了一組標(biāo)準(zhǔn)的實(shí)現(xiàn)接口,這些接口一般都是和具體的產(chǎn)品類繼承層次對(duì)應(yīng)的。如createProductA接口只能生產(chǎn)抽象產(chǎn)品類(AbstratctProductA)的子類產(chǎn)品,因此抽象工廠的具體實(shí)現(xiàn)類之間的關(guān)系就是個(gè)生產(chǎn)了一批不同產(chǎn)品族的組合。這樣通過抽象工廠模式可以方便的更換產(chǎn)品族,代碼修改的代價(jià)只需要更換一個(gè)具體的工廠對(duì)象就可以了。因此直觀上可以把抽象工廠看作一組工廠方法,它的每一個(gè)接口都可以提取出一個(gè)單獨(dú)的工廠方法。不過抽象工廠除了反映出這些含義外,還隱含著多類產(chǎn)品之間有種內(nèi)在的聯(lián)系,如按鈕、菜單、滾動(dòng)條都是GUI組件。
舉例:
對(duì)于可以隨意更換GUI組件庫(kù)的需求,抽象工廠就可以完成類似的功能。抽象工廠類(AbstractFactory)封裝了GUI組件庫(kù)必須提供的接口,如創(chuàng)建按鈕、菜單、滾動(dòng)條等。GUI組件類會(huì)根據(jù)不同的窗口系統(tǒng)而派生具體的組件類,實(shí)現(xiàn)抽象工廠的具體類具體工廠類會(huì)根據(jù)不同的窗口系統(tǒng)選擇對(duì)應(yīng)的組件進(jìn)行生產(chǎn)。這樣當(dāng)更換窗口系統(tǒng)的時(shí)候,只需要更換工廠類就能方便的實(shí)現(xiàn)運(yùn)行時(shí)窗口系統(tǒng)的更換。按照這樣的描述,我們用C++實(shí)現(xiàn)的代碼如下:

//產(chǎn)品類繼承層次
class Button
{
     public:
     virtual void click()=0;
     virtual ~Button(){}
};

class WindowsButton:public Button
{
    public:
    virtual void click()
    {
        cout<<"單擊了Windows按鈕"<<endl;
    }
};

class MacButton:public Button
{
   public:
   virtual void click()
   {
       cout<<"單擊了Mac按鈕"<<endl;
   }
};

class Menu
{
    public:
    virtual void select()=0;
    virtual ~Menu(){}
};

class WindowsMenu:public Menu
{
    public:
    virtual void select()
    {
        cout<<"選擇了Windows菜單"<<endl;
    }
};

class MacMenu:public Menu
{
    public:
    virtual void select()
    {
         cout<<"選擇了Mac菜單"<<endl;
    }
};

//抽象工廠
class GUIFactory
{
    public:
    virtual Button*createButton()=0;
    virtual Menu*createMenu()=0;
    virtual ~GUIFactory(){}
};

//具體的工廠
class WindowsGUIFactory:public GUIFactory
{
    public:
    virtual Button*createButton()
    {
          return new WindowsButton();
    }

    virtual Menu*createMenu()
    {
         return new WindowsMenu();
    }
};

class MacGUIFactory:public GUIFactory
{
    public:
    virtual Button*createButton()
    {
         return new MacButton();
    }

    virtual Menu*createMenu()
    {
         return new MacMenu();
    }
};

如果我們使用這段代碼創(chuàng)建組件,就會(huì)這么寫了:

GUIFactory*factory=new WindowsGUIFactory();//創(chuàng)建工廠
Button*btn=factory->createButton();//創(chuàng)建按鈕
Menu*menu=factory->createMenu();//創(chuàng)建菜單
btn->click();//調(diào)用組件函數(shù)
menu->select();
delete menu;
delete btn;
delete factory;

從代碼中看出我們無法看到看到具體創(chuàng)建的組件,因?yàn)槲覀冎恍枰贸橄箢怋utton、Menu使用標(biāo)準(zhǔn)的接口就可以了,具體的實(shí)現(xiàn)被工廠封裝起來了。如果我們要更換所有的一批組件的話,只需要修改第一行代碼,換一個(gè)工廠就可以了。

下面用Objective-C語(yǔ)言寫個(gè)抽象工廠的例子。
工廠父類:抽象工廠

#import <Foundation/Foundation.h>
#import "BasePhone.h"
#import "BaseWatch.h"

@interface BaseFactory : NSObject

/**
  *  創(chuàng)建手機(jī)
  *
  *  @return 手機(jī)
  */
- (BasePhone *)createPhone;

/**
  *  創(chuàng)建手表
  *
  *  @return 手表
  */
 - (BaseWatch *)createWatch;

@end

#import "BaseFactory.h"

@implementation BaseFactory

- (BasePhone *)createPhone {

     return nil;
}

- (BaseWatch *)createWatch {

     return nil;
}

@end

工廠子類:具體工廠

// 蘋果工廠
#import "BaseFactory.h"

@interface AppleFactory : BaseFactory

@end

#import "AppleFactory.h"
#import "iPhone.h"
#import "AppleWatch.h"

@implementation AppleFactory

- (BasePhone *)createPhone {

     return [[iPhone alloc] init];
}

- (BaseWatch *)createWatch {

     return [[AppleWatch alloc] init];
}

// 谷歌工廠
#import "BaseFactory.h"

@interface GoogleFactory : BaseFactory

@end

#import "GoogleFactory.h"
#import "Android.h"
#import "AndroidWatch.h"

@implementation GoogleFactory

- (BasePhone *)createPhone {

    return [[Android alloc] init];
}

- (BaseWatch *)createWatch {

     return [[AndroidWatch alloc] init];
}

@end

具體的設(shè)備也是先創(chuàng)建設(shè)備的父類BasePhone和BaseWatch,再創(chuàng)建繼承自它們倆的子類iPhone,Android,AppleWatch,AndroidWatch。

工廠管理類

#import <Foundation/Foundation.h>
#import "BaseFactory.h"
#import "AppleFactory.h"
#import "GoogleFactory.h"

typedef NS_ENUM(NSUInteger, EFactoryType) {

     kApple   = 0x11,
     kGoogle,

};

@interface FactoryManager : NSObject

/**
  *  獲取工廠
  *
  *  @param factoryType 工廠類型
  *
  *  @return 創(chuàng)建出的工廠
  */
 + (BaseFactory *)factoryWithBrand:(EFactoryType)factoryType;

 @end

 #import "FactoryManager.h"

 @implementation FactoryManager

 + (BaseFactory *)factoryWithBrand:(EFactoryType)factoryType {

      BaseFactory *factory = nil;

      if (factoryType == kApple) {
    
           factory = [[AppleFactory alloc] init];
    
      } else if (factoryType == kGoogle) {

           factory = [[GoogleFactory alloc] init];
      }

      return factory;
}

@end

具體工廠的創(chuàng)建方法如下:

// 獲取工廠
BaseFactory *factory = [FactoryManager factoryWithBrand:kGoogle];

// 創(chuàng)建商品
BasePhone *phone = [factory createPhone];
BaseWatch *watch = [factory createWatch];

簡(jiǎn)單工廠模式

手機(jī)協(xié)議
#import <Foundation/Foundation.h>

@protocol PhoneProtocol <NSObject>

@required

/**
  *  打電話
  */
- (void)phoneCall;

/**
  *  發(fā)短信
  */
- (void)sendMessage;

@end

設(shè)備父類
BaseDevice.h
#import <Foundation/Foundation.h>
#import "PhoneProtocol.h"

@interface BaseDevie : NSObject <PhoneProtocol>

@end

BaseDevice.m
#import "BaseDevie.h"

@implementation BaseDevie

- (void)phoneCall {

}

- (void)sendMessage {

}

@end

具體設(shè)備
iPhone設(shè)備
#import "BaseDevie.h"

@interface iPhoneDevice : BaseDevie

/**
  *  指紋識(shí)別
  */
- (void)fingerprintIndetification;

@end

#import "iPhoneDevice.h"

@implementation iPhoneDevice

- (void)phoneCall {

     NSLog(@"iPhone phoneCall");
}

- (void)sendMessage {

     NSLog(@"iPhone sendMessage");
}

- (void)fingerprintIndetification {

     NSLog(@"iPhone fingerprintIndetification");
}

@end

Android設(shè)備
#import "BaseDevie.h"

@interface AndroidDevice : BaseDevie

/**
 *  定制主題
 */
- (void)customTheme;

@end

#import "AndroidDevice.h"

@implementation AndroidDevice

- (void)phoneCall {

     NSLog(@"Android phoneCall");
}

- (void)sendMessage {

     NSLog(@"Android sendMessage");
}

- (void)customTheme {

     NSLog(@"Android customTheme");
}

@end

手機(jī)設(shè)備工廠
#import <Foundation/Foundation.h>
#import "BaseDevie.h"
#import "iPhoneDevice.h"
#import "AndroidDevice.h"

typedef NS_ENUM(NSUInteger, EDevieType) {

     kiPhone   = 0x11,
     kAndroid,

} ;

@interface DeviceFactory : NSObject

/**
 *  根據(jù)用戶提交的指令創(chuàng)建出具體的手機(jī)
 *
 *  @param type 創(chuàng)建的指令
 *
 *  @return 創(chuàng)建出的手機(jī)
 */
+ (BaseDevie <PhoneProtocol> *)deviceFactoryWithDevieType:(EDevieType)type;

@end

#import "DeviceFactory.h"

@implementation DeviceFactory

+ (BaseDevie <PhoneProtocol> *)deviceFactoryWithDevieType:(EDevieType)type {

    BaseDevie <PhoneProtocol> *device = nil;

    if (type == kiPhone) {
    
        device = [[iPhoneDevice alloc] init];
    
    }  else if (type == kAndroid) {

        device = [[AndroidDevice alloc] init];
    
    }  

    return device;
}

@end

簡(jiǎn)單工廠實(shí)現(xiàn)

// 工廠中創(chuàng)建出具體產(chǎn)品
iPhoneDevice *iPhone = (iPhoneDevice *)[DeviceFactory deviceFactoryWithDevieType:kiPhone];

// 使用產(chǎn)品的功能
[iPhone fingerprintIndetification];

工廠模式是最重要的模式,因?yàn)榇蠖鄶?shù)模式都需要用到工廠模式。如果不能正確的運(yùn)用工廠模式,那么可以說無法成為合格的架構(gòu)師。

工廠方法模式:

一個(gè)抽象產(chǎn)品類,可以派生出多個(gè)具體產(chǎn)品類。   
一個(gè)抽象工廠類,可以派生出多個(gè)具體工廠類。
每個(gè)具體工廠類只能創(chuàng)建一個(gè)具體產(chǎn)品類的實(shí)例。

抽象工廠模式:

多個(gè)抽象產(chǎn)品類,每個(gè)抽象產(chǎn)品類可以派生出多個(gè)具體產(chǎn)品類。
一個(gè)抽象工廠類,可以派生出多個(gè)具體工廠類。
每個(gè)具體工廠類可以創(chuàng)建多個(gè)具體產(chǎn)品類的實(shí)例。

區(qū)別:
工廠方法模式只有一個(gè)抽象產(chǎn)品類,而抽象工廠模式有多個(gè)。
工廠方法模式的具體工廠類只能創(chuàng)建一個(gè)具體產(chǎn)品類的實(shí)例,而抽象工廠模式可以創(chuàng)建多個(gè)。

在iOS的系統(tǒng)類庫(kù)中也有一種方式使得開發(fā)者不必關(guān)注類中具體的存儲(chǔ)實(shí)現(xiàn),但可以根據(jù)不同需求場(chǎng)景創(chuàng)建出合適的對(duì)象來。

在iOS中有很多類都是使用了工廠模式,例如
Foundation:
NSNumber,
NSArray,
UIKit:
UIButton等類。

最后編輯于
?著作權(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ù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 工廠方法模式通過引入工廠等級(jí)結(jié)構(gòu),解決了簡(jiǎn)單工廠模式中工廠類職責(zé)太重的問題,但由于工廠方法模式中的每個(gè)工廠只生產(chǎn)一...
    justCode_閱讀 1,300評(píng)論 1 6
  • 設(shè)計(jì)原則: 要依賴抽象,不要依賴具體類 目錄 本文的結(jié)構(gòu)如下: 什么是抽象工廠模式 為什么要用該模式 模式的結(jié)構(gòu) ...
    w1992wishes閱讀 1,245評(píng)論 0 6
  • 一、工廠模式介紹 工廠模式專門負(fù)責(zé)將大量有共同接口的類實(shí)例化。工廠模式可以動(dòng)態(tài)決定將哪一個(gè)類實(shí)例化,不必事先知道每...
    端木軒閱讀 13,009評(píng)論 1 20
  • 早晨起床,我收拾一堆好洗的衣服。往洗手間走的路上不小心掉了一件“寶貝兒,能幫媽媽把地上的衣服放到洗衣機(jī)上嗎?”我邊...
    相信就會(huì)看到閱讀 201評(píng)論 0 1
  • 2017年11月3日,星期五,微風(fēng)正好,陽(yáng)光稍燥。 下午后兩節(jié)興趣課,跟振玲姐商議在室外綠茵場(chǎng)上兩個(gè)班進(jìn)行...
    生如霞霞花閱讀 712評(píng)論 2 1

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