工廠方法與抽象工廠的迷之理解

  • 工廠方法

其實我也想著
有一天程序員做不下去了
頭發(fā)也掉光了
就回老家
老婆孩子熱炕頭的
開一家花生油店
畢竟家里祖?zhèn)鞯氖炙嚥荒軄G
這樣的話, 我首先就需要一個生產(chǎn)花生油實例的花生油類 : HXPeanutOil :

//HXPeanutOil.h

#import <Foundation/Foundation.h>

@interface HXPeanutOil : NSObject
- (void)smellSmell;
@end
// HXPeanutOil.m

#import "HXPeanutOil.h"

@implementation HXPeanutOil
- (void)smellSmell {
    NSLog(@"我是花生油, 我是花生油的味道");
}
@end

當然想要生產(chǎn)花生油
得有個小作坊, 也就是工廠

// HXPeanutOilFactory.h

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

@interface HXPeanutOilFactory : NSObject
+ (HXPeanutOil *)createOil;
@end

// HXPeanutOilFactory.m

#import "HXPeanutOilFactory.h"

@implementation HXPeanutOilFactory

+ (HXPeanutOil *)createOil {
    return [[HXPeanutOil alloc] init];
}

@end

這樣基本就可以開工了
但是!
作為一個頭發(fā)都禿光了的資深程序員
怎么能如此目光短淺
只生產(chǎn)花生油呢
哪天客戶要我生產(chǎn)玉米油咋整
學以致用
繼承搞起來
多態(tài)搞起來

于是
抽象工廠就誕生了 :

// HXOilFactory.h

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

@interface HXOilFactory : NSObject
+ (HXOil *)createOil;
@end

// HXOilFactory.m

#import "HXOilFactory.h"

@implementation HXOilFactory
+ (HXOil *)createOil {
    return nil;
}
@end

于是
抽象產(chǎn)品也就誕生了 :

// HXOil.h

#import <Foundation/Foundation.h>

@interface HXOil : NSObject
- (void)smellSmell;
@end
// HXOil.m

#import "HXOil.h"

@implementation HXOil
- (void)smellSmell {
    
}
@end

讓之前花生油工廠 HXPeanutOilFactory 繼承抽象工廠 HXOilFactory, 并把的生產(chǎn)操作 createOil 提取到父類
讓之前花生油產(chǎn)品 HXPeanutOil 繼承抽象產(chǎn)品 HXOil, 并把的聞一聞操作 smellSmell 提取到父類
這樣的話, 看起來舒適很多
如果這時候花生油生意做大了
出于對我產(chǎn)油能力的肯定, 客戶非要我生產(chǎn)玉米油
這樣的話玉米油工廠只需要繼承 HXOilFactory 創(chuàng)建 HXMaizeOilFactory
公用的生產(chǎn)操作已經(jīng)在父類中聲明

// HXMaizeOilFactory.h

#import "HXOilFactory.h"

@interface HXMaizeOilFactory : HXOilFactory

@end
// HXMaizeOilFactory.m

#import "HXMaizeOilFactory.h"
#import "HXMaizeOil.h"

@implementation HXMaizeOilFactory

+ (HXMaizeOil *)createOil {
    return [[HXMaizeOil alloc] init];
}

@end

然后玉米油就是繼承 HXOil 的 HXMaizeOil
同樣公用的聞一聞操作也已經(jīng)在父類中已經(jīng)聲明

// HXMaizeOil.h

#import "HXOil.h"

@interface HXMaizeOil : HXOil

@end
// HXMaizeOil.m

#import "HXMaizeOil.h"

@implementation HXMaizeOil

- (void)smellSmell {
    NSLog(@"我是玉米油, 我是玉米油的味道");
}

@end

這樣以來
就可以完美的生產(chǎn)出玉米油
客戶只需要像讓我生產(chǎn)花生油那樣
告訴我生產(chǎn)玉米油
就可以生產(chǎn)玉米油了
不需要客戶端做額外操作
如果客戶有一天覺得這些油都不好吃了
想嘗一嘗地溝油
那么只需要繼承 HXOilFactory 創(chuàng)建地溝油工廠類
繼承 HXOil 創(chuàng)建地溝油產(chǎn)品類
就可以生產(chǎn)地溝油給客戶啦

例如生產(chǎn)玉米油, 大概就像這個樣子 :

- (void)createMaizeOil {
    HXOil *oil = [HXMaizeOilFactory createOil];
    [oil smellmell];
}
總結(jié) :

工廠方法模式中的參與者:
抽象工廠角色:工廠模式的基類,定義了公共接口
具體工廠角色:實現(xiàn)了抽象工廠類的接口,是與客戶端直接交互的類,負責具體的產(chǎn)品對象的創(chuàng)建
抽象產(chǎn)品角色:是具體產(chǎn)品類的基類,定義了公共接口
具體產(chǎn)品角色:實現(xiàn)了抽象產(chǎn)品類接口,每一個具體產(chǎn)品類都會對應一個工廠

  • 抽象工廠

發(fā)現(xiàn)回到家之后
油坊火了
實現(xiàn)財富自由了
沒辦法啊,怎么辦呢?
創(chuàng)品牌吧!
品牌就叫擼花花生油
然后又給自己的品牌設計了
一個個性油桶和一個個性 Logo
油桶和 Logo 哪里來?
自產(chǎn)!
要生產(chǎn)油桶和 Logo
也得要工廠啊
瞅了瞅自己的花生油玉米油和地溝油的油廠
油廠只能生產(chǎn)油
想讓油廠產(chǎn)油桶和 logo 估計也不好使
重新建廠! 有錢!
軟件設計的黃金法則 : 變動需要抽象!
于是抽象工廠 HXOilAccessoryFactory 類誕生了 :

// HXOilAccessoryFactory.h

#import <Foundation/Foundation.h>
#import "HXOilLogo.h"
#import "HXOilContainer.h"

typedef NS_ENUM(NSUInteger, HXOilType) {
    /** 擼花花生油 */
    HXOilTypeLuHuaOil
};

@interface HXOilAccessoryFactory : NSObject

+ (HXOilAccessoryFactory *)factoryWithType:(HXOilType)type;

- (HXOilLogo *)createOilLogo;
- (HXOilContainer *)createilContainer;

@end
// HXOilAccessoryFactory.m

#import "HXOilAccessoryFactory.h"
#import "HXLuHuaOilAccessoryFactory.h"

@implementation HXOilAccessoryFactory

+ (HXOilAccessoryFactory *)factoryWithType:(HXOilType)type {
    if (type == HXOilTypeLuHuaOil) {
        return [[HXLuHuaOilAccessoryFactory alloc] init];
    }else {
        return nil;
    }
}

- (HXOilLogo *)createOilLogo {
    return nil;
}

- (HXOilContainer *)createilContainer {
    return nil;
}

@end

這個類干這么2件事 :
根據(jù)客戶需求, 返回具體工廠
聲明了每個具體工廠都需要實現(xiàn)的接口(生產(chǎn) Logo 接口,和生產(chǎn)油桶接口)

然后就是我們創(chuàng)的品牌擼花花生油的具體工廠
繼承自 HXOilAccessoryFactory 的 HXLuHuaOilAccessoryFactory

// HXLuHuaOilAccessoryFactory.h
#import "HXOilAccessoryFactory.h"

@interface HXLuHuaOilAccessoryFactory : HXOilAccessoryFactory

@end
// HXLuHuaOilAccessoryFactory.m

#import "HXLuHuaOilAccessoryFactory.h"
#import "HXLuHuaOilLogo.h"
#import "HXLuHuaOilContainer.h"

@implementation HXLuHuaOilAccessoryFactory

- (HXOilLogo *)createOilLogo {
    return [[HXLuHuaOilLogo alloc] init];
}

- (HXOilContainer *)createilContainer {
    return [[HXLuHuaOilContainer alloc] init];
}

@end

他用來生產(chǎn)實體 Logo 和實體油桶
生產(chǎn)出的油桶是 HXLuHuaOilContainer
Logo 就是 HXLuHuaOilLogo
HXLuHuaOilContainer 繼承抽象產(chǎn)品類 HXOilContainer
HXLuHuaOilLogo 繼承抽象產(chǎn)品類 HXOilLogo
他們的實現(xiàn)分別如下 :

// HXOilLogo.h
// Logo 的抽象父類

#import <Foundation/Foundation.h>

@interface HXOilLogo : NSObject

- (void)color;
- (void)appearance;

@end
// HXOilLogo.m

#import "HXOilLogo.h"

@implementation HXOilLogo

- (void)color {
    
}

- (void)appearance {
    
}

@end
// HXLuHuaOilLogo.h
// 我是擼花花生油 Logo 的實體類

#import "HXOilLogo.h"

@interface HXLuHuaOilLogo : HXOilLogo

@end
// HXLuHuaOilLogo.m

#import "HXLuHuaOilLogo.h"

@implementation HXLuHuaOilLogo

- (void)color {
    NSLog(@"我是擼花花生油 Logo, 我是黃色");
}

- (void)appearance {
    NSLog(@"我是擼花花生油 Logo, 我是三角形");
}

@end

// HXOilContainer.h
// 油桶 OilContainer 的抽象父類

#import <Foundation/Foundation.h>

@interface HXOilContainer : NSObject

- (void)name;
- (void)size;

@end
// HXOilContainer.m

#import "HXOilContainer.h"

@implementation HXOilContainer

- (void)name {
    
}

- (void)size {
    
}

@end
// HXLuHuaOilContainer.h
// 擼花花生油的油桶實體類

#import "HXOilContainer.h"

@interface HXLuHuaOilContainer : HXOilContainer

@end
// HXLuHuaOilContainer.m

#import "HXLuHuaOilContainer.h"

@implementation HXLuHuaOilContainer

- (void)name {
    NSLog(@"我是擼花花生油油桶");
}

- (void)size {
    NSLog(@"我是擼花花生油油桶 -- 我能裝3L");
}

@end

對于 Logo
他有 color 和 appearance 兩個操作
都已在抽象父類中聲明
實體子類來具體實現(xiàn)

對于 OilContainer
他有 name 和 size 兩個操作
都已在抽象父類中聲明
實體子類來具體實現(xiàn)

客戶端的調(diào)用 :

- (void)abstractFactory {
    HXOilAccessoryFactory *factory = [HXOilAccessoryFactory factoryWithType:HXOilTypeLuHuaOil];
    HXOilLogo *logo = [factory createOilLogo];
    HXOilContainer *container = [factory createilContainer];
    [logo color];
    [logo appearance];
    [container name];
    [container size];
}

打印是這個樣子 :

2018-08-07 16:25:40.115446+0800  我是擼花花生油 Logo, 我是黃色
2018-08-07 16:25:40.115597+0800  我是擼花花生油 Logo, 我是三角形
2018-08-07 16:25:40.115894+0800  我是擼花花生油油桶
2018-08-07 16:25:40.115974+0800  我是擼花花生油油桶 -- 我能裝3L

到此為止
已經(jīng)可以完美的生產(chǎn)擼花花生油的 Logo 和油桶(OilContainer)了
可是久而久之
客戶吃夠了擼花花生油
沒辦法, 他們總是喜新厭舊的
然后客戶提出了新需求 : 我還是想吃地溝油
怎么辦呢?
產(chǎn)啊, 地溝油油桶, 地溝油 Logo 都要產(chǎn)
先建廠 HXDiGouOilAccessoryFactory 繼承自剛才的抽象工廠 HXOilAccessoryFactory

// HXDiGouOilAccessoryFactory.h

#import "HXOilAccessoryFactory.h"

@interface HXDiGouOilAccessoryFactory : HXOilAccessoryFactory

@end
// HXDiGouOilAccessoryFactory.m

#import "HXDiGouOilAccessoryFactory.h"
#import "HXDiGouOilLogo.h"
#import "HXDiGouOilContainer.h"

@implementation HXDiGouOilAccessoryFactory

- (HXOilLogo *)createOilLogo {
    return [[HXDiGouOilLogo alloc] init];
}

- (HXOilContainer *)createilContainer {
    return [[HXDiGouOilContainer alloc] init];
}

@end

然后創(chuàng)建產(chǎn)品 HXDiGouOilLogo 繼承自 HXOilLogo
然后創(chuàng)建產(chǎn)品 HXDiGouOilContainer 繼承自 HXOilContainer
實現(xiàn)如下 ;

// HXDiGouOilLogo.h
// 我是地溝油 Logo

#import "HXOilLogo.h"

@interface HXDiGouOilLogo : HXOilLogo

@end
// HXDiGouOilLogo.m

#import "HXDiGouOilLogo.h"

@implementation HXDiGouOilLogo

- (void)color {
    NSLog(@"我是地溝油 Logo, 我是棕色");
}

- (void)appearance {
    NSLog(@"我是地溝油 Logo, 我是心形");
}

@end
// HXDiGouOilContainer.h
// 地溝油的油桶

#import "HXOilContainer.h"

@interface HXDiGouOilContainer : HXOilContainer

@end
// HXDiGouOilContainer.m
#import "HXDiGouOilContainer.h"

@implementation HXDiGouOilContainer

- (void)name {
    NSLog(@"我是地溝油油桶");
}

- (void)size {
    NSLog(@"我是地溝油油桶 -- 我能裝50L");
}

@end

調(diào)用的話 就可以這么搞 :

//抽象工廠
- (void)abstractFactory {
    HXOilAccessoryFactory *factory = [HXOilAccessoryFactory factoryWithType:HXOilTypeDiGouOil];
    HXOilLogo *logo = [factory createOilLogo];
    HXOilContainer *container = [factory createilContainer];
    [logo color];
    [logo appearance];
    [container name];
    [container size];
}

打印將是這樣 :

2018-08-07 16:53:18.718973+0800  我是地溝油 Logo, 我是棕色
2018-08-07 16:53:18.719095+0800  我是地溝油 Logo, 我是心形
2018-08-07 16:53:18.719209+0800  我是地溝油油桶
2018-08-07 16:53:18.719333+0800  我是地溝油油桶 -- 我能裝50L

到這里為止
已經(jīng)可以完美的生產(chǎn)地溝油
滿足了客戶想吃地溝油的心情
思路大概就是這樣
以后增加新品種
就建新廠
搞新產(chǎn)品

抽象工廠的總結(jié)以及與工廠方法的區(qū)別 :

抽象工廠模式提供一個創(chuàng)建一系列相關或相互依賴的對象的接口
而無需指定它們具體的類(就像我們創(chuàng)建的具體工廠實例, 都是用抽象工廠的指針指向他, 其實指針并不知道自己指向的是地溝油實例, 還是花生油實例)
那么工廠模式和抽象工廠模式的區(qū)別是什么呢?
這兩種設計模式主要的區(qū)別在于產(chǎn)品
工廠模式是用來創(chuàng)建同一個產(chǎn)品的不同類型
比如說產(chǎn)油, 花生油, 玉米油, 地溝油, 都是油
但是抽象工廠模式是用來創(chuàng)建一系列相關不同類型的產(chǎn)品
比如油坊還想自己產(chǎn)一些 Logo 和油桶
剛才創(chuàng)建的油廠就不能產(chǎn)這些東西了, 就要重新建廠
一般來說,產(chǎn)品種類單一,適合用工廠模式
如果有多個種類,各種類型時,通過抽象工廠模式來進行創(chuà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ā)布平臺,僅提供信息存儲服務。

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