哲學(xué)上說“是什么,為什么,怎么用”是認(rèn)識(shí)問題的邏輯思維過程.
本文將以廠長工廠造車為例子講述這三種設(shè)計(jì)模式蜻势。
簡單工廠模式
是什么
簡單工廠模式是屬于創(chuàng)建型模式撑刺,又叫做靜態(tài)工廠方法(Static Factory Method)模式,但不屬于23種GOF設(shè)計(jì)模式之一握玛。簡單工廠模式是由一個(gè)工廠對(duì)象決定創(chuàng)建出哪一種產(chǎn)品類的實(shí)例够傍。
簡單工廠模式主要包含三部分:
工廠類角色:本模式核心,含有商業(yè)邏輯和判斷邏輯挠铲,根據(jù)邏輯不同冕屯,生產(chǎn)具體的工廠產(chǎn)品。
抽象產(chǎn)品角色:定義了工廠方法創(chuàng)建的對(duì)象的接口拂苹。由接口或者抽象類來實(shí)現(xiàn)安聘。
具體產(chǎn)品角色:工廠類所創(chuàng)建的對(duì)象就是此實(shí)例。由具體類實(shí)現(xiàn)瓢棒。
怎么用
第一年:生意來了浴韭,老板就一個(gè)廠要造benz,audi的脯宿。
#import "CarSampleFactory.h"
@implementation CarSampleFactory
// 抽象產(chǎn)品就是具體產(chǎn)品的接口囱桨,直接用一句話代替了
-(void)createCarWithName:(NSString *)name {
NSArray *car = @[@"Benz", @"BMW", @"Audi"];
NSUInteger index = [car indexOfObject:name];
switch (index) {
case 0:
NSLog(@"生產(chǎn)了Benz具體產(chǎn)品(alloc你需要的類)");
break;
case 1:
NSLog(@"生產(chǎn)了Audi具體產(chǎn)品");
break;
default:
break;
}
}
@end
為什么
- 優(yōu)點(diǎn)
工廠類是整個(gè)模式的關(guān)鍵.包含了必要的邏輯判斷,根據(jù)外界給定的信息,決定究竟應(yīng)該創(chuàng)建哪個(gè)具體類的對(duì)象.通過使用工廠類,僅僅需要負(fù)責(zé)“消費(fèi)”對(duì)象就可以了。而不必管這些對(duì)象究竟如何創(chuàng)建的嗅绰。所以也稱之‘上帝類’舍肠。 - 缺點(diǎn)
由于工廠類集中了所有實(shí)例的創(chuàng)建邏輯,違反了高內(nèi)聚責(zé)任分配原則窘面,將全部創(chuàng)建邏輯集中到了一個(gè)工廠類中翠语。每增加一種品牌的車子,都要修改邏輯判斷處代碼财边。不符合開閉原則,肌括。
這些缺點(diǎn)在工廠方法模式中得到了一定的克服。
工廠模式
是什么
工廠方法模式是一種常用的對(duì)象創(chuàng)建型設(shè)計(jì)模式,此模式的核心精神是封裝類中不變的部分,提取其中個(gè)性化善變的部分為獨(dú)立類谍夭,通過依賴注入以達(dá)到解耦黑滴、復(fù)用和方便后期維護(hù)拓展的目的。
- 抽象工廠(Creator)角色:是工廠方法模式的核心紧索,與應(yīng)用程序無關(guān)袁辈。任何在模式中創(chuàng)建的對(duì)象的工廠類必須實(shí)現(xiàn)這個(gè)接口或者繼承。
- 具體工廠(Concrete Creator)角色:這是實(shí)現(xiàn)抽象工廠接口的具體工廠類珠漂,包含與應(yīng)用程序密切相關(guān)的邏輯晚缩,并且受到應(yīng)用程序調(diào)用以創(chuàng)建產(chǎn)品對(duì)象。
- 抽象產(chǎn)品(Product)角色:工廠方法模式所創(chuàng)建的對(duì)象的超類型媳危,也就是產(chǎn)品對(duì)象的共同父類或共同擁有的接口荞彼。
- 具體產(chǎn)品(Concrete Product)角色:這個(gè)角色實(shí)現(xiàn)了抽象產(chǎn)品角色所定義的接口。某具體產(chǎn)品有專門的具體工廠創(chuàng)建待笑,它們之間往往一一對(duì)應(yīng)鸣皂。(benz車)
怎么用
第二年:生意越做越大,Audi啊來了暮蹂,廠子忙不過了寞缝。聰明的廠長又開了三個(gè)廠子,并且叫了一個(gè)管理者(抽象工廠)來管理這些工廠椎侠。
#import "ViewController.h"
// 工廠方法
// 第一種情況是對(duì)于某個(gè)產(chǎn)品第租,調(diào)用者清楚地知道應(yīng)該使用哪個(gè)具體工廠服務(wù),實(shí)例化該具體工廠我纪,生產(chǎn)出具體的產(chǎn)品來慎宾。
BMWFactory *BMWF = [[BMWFactory alloc] init];
[BMWF CreateCarBMW];
// 第二種情況,只是需要一種產(chǎn)品浅悉,而不想知道也不需要知道究竟是哪個(gè)工廠為生產(chǎn)的趟据,即最終選用哪個(gè)具體工廠的決定權(quán)在生產(chǎn)者一方,它們根據(jù)當(dāng)前系統(tǒng)的情況來實(shí)例化一個(gè)具體的工廠返回給使用者术健,而這個(gè)決策過程這對(duì)于使用者來說是透明的(類似多態(tài))
CarAbstractFactory *caf = [[BMWFactory alloc] init];
[caf CreateCarFactoy];
caf = [[BenzFactory alloc] init];
[caf CreateCarFactoy];
#import "CarAbstractFactory.h"
@implementation CarAbstractFactory
//抽象工廠
-(void)CreateCarFactoye{
}
@end
#import "BenzFactory.h"
//具體工廠
@implementation BenzFactory
-(void)CreateCarFactoy{
[self CreateCarBenz];
}
- (void)CreateCarBenz{
//具體產(chǎn)品
NSLog(@"工廠方法生產(chǎn)了Benz具體產(chǎn)品(alloc你需要的類)");
}
@end
#import "BMWFactory.h"
@implementation BMWFactory
-(void)CreateCarFactoy{
[self CreateCarBMW];
}
- (void)CreateCarBMW{
NSLog(@"工廠方法生產(chǎn)了BMW具體產(chǎn)品(alloc你需要的類)");
}
@end
#import "AudiFactory.h"
@implementation AudiFactory
-(void)CreateCarFactoy{
[self CreateCarAudi];
}
- (void)CreateCarAudi{
NSLog(@"工廠方法生產(chǎn)了Benz具體產(chǎn)品(alloc你需要的類)");
}
@end
為什么
優(yōu)點(diǎn)
工廠方法模式是簡單工廠模式的衍生汹碱,相當(dāng)于橫向擴(kuò)展。當(dāng)有新的產(chǎn)品(法拉利汽車)荞估,只要新建繼承抽象工廠的類就好了咳促。完全符合繼承原則。缺點(diǎn)
但是產(chǎn)品種類特別多的時(shí)候勘伺,就會(huì)產(chǎn)生大量的工廠類跪腹。所以對(duì)于類似的產(chǎn)品我們還是用簡單工廠來實(shí)現(xiàn)。復(fù)雜的業(yè)務(wù)邏輯可以使用兩者結(jié)合的模式飞醉。開發(fā)者依照自身取舍冲茸。
可是benz和audi等工廠突然又想生產(chǎn)自己suv,跑車等等,那只能在工廠里寫個(gè)各種邏輯判斷,好吧轴术,又違反了開閉原則难衰,又回到類似簡單工廠的弊端。這時(shí)候就需要用到抽象工廠模式逗栽。
抽象工廠模式
是什么
是工廠方法設(shè)計(jì)模式的一種擴(kuò)展盖袭。當(dāng)有多個(gè)抽象角色時(shí),使用的一種工廠模式祭陷。
- AbstractFactory(抽象工廠):它聲明了一組用于創(chuàng)建一族產(chǎn)品的方法苍凛,每一個(gè)方法對(duì)應(yīng)一種產(chǎn)品趣席。
- ConcreteFactory(具體工廠):它實(shí)現(xiàn)了在抽象工廠中聲明的創(chuàng)建產(chǎn)品的方法兵志,生成一組具體產(chǎn)品,這些產(chǎn)品構(gòu)成了一個(gè)產(chǎn)品族宣肚,每一個(gè)產(chǎn)品都位于某個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)中想罕。
- AbstractProduct(抽象產(chǎn)品):它為每種產(chǎn)品聲明接口,在抽象產(chǎn)品中聲明了產(chǎn)品所具有的業(yè)務(wù)方法霉涨。
- ConcreteProduct(具體產(chǎn)品):它定義具體工廠生產(chǎn)的具體產(chǎn)品對(duì)象按价,實(shí)現(xiàn)抽象產(chǎn)品接口中聲明的業(yè)務(wù)方法。
- 產(chǎn)品等級(jí)結(jié)構(gòu):產(chǎn)品等級(jí)結(jié)構(gòu)即產(chǎn)品的繼承結(jié)構(gòu)(三種品牌汽車構(gòu)成了三個(gè)不同的產(chǎn)品等級(jí)結(jié)構(gòu))
- 產(chǎn)品族:在抽象工廠模式中笙瑟,產(chǎn)品族是指由同一個(gè)工廠生產(chǎn)的楼镐,位于不同產(chǎn)品等級(jí)結(jié)構(gòu)中的一組產(chǎn)品。比如(suv工廠里生產(chǎn)的三個(gè)品牌車型)
怎么用
第三年:audi往枷,benz框产,bmw告訴廠長,我們這次的訂單需要分成suv错洁,business秉宿,sport三種類型的車。這時(shí)候管理蠻不過來了屯碴。所以廠子又請(qǐng)了兩個(gè)管理描睦。分別管理三個(gè)品牌的車子。
// 抽象工廠兩種情況同工廠方法上
// method 1
SUVFactory *suvf = [[SUVFactory alloc] init];
[suvf createAudiCar];
// method 2
AbstractFactorys *af = [[SportsFactorys alloc] init];
[af CreateAudiFactoy];
#import <Foundation/Foundation.h>
@interface AbstractFactorys : NSObject
//抽象工廠(三個(gè)管理者)
-(void)CreateBenzFactoy;
-(void)CreateBMWFactoy;
-(void)CreateAudiFactoy;
@end
#import "SUVFactory.h"
//具體工廠
@implementation SUVFactory
-(void)createBenzCar{
NSLog(@"抽象工廠方法生產(chǎn)了benzSUV");
}
-(void)createBWMCar{
NSLog(@"抽象工廠方法生產(chǎn)了BWMSUV");
}
-(void)createAudiCar{
NSLog(@"抽象工廠方法生產(chǎn)了AudiSUV");
}
@end
為什么
抽象工廠模式與工廠方法模式最大的區(qū)別在于导而,工廠方法模式針對(duì)的是一個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)忱叭,而抽象工廠模式需要面對(duì)多個(gè)產(chǎn)品等級(jí)結(jié)構(gòu),一個(gè)工廠等級(jí)結(jié)構(gòu)可以負(fù)責(zé)多個(gè)不同產(chǎn)品等級(jí)結(jié)構(gòu)中的產(chǎn)品對(duì)象的創(chuàng)建今艺。當(dāng)一個(gè)工廠等級(jí)結(jié)構(gòu)可以創(chuàng)建出分屬于不同產(chǎn)品等級(jí)結(jié)構(gòu)的一個(gè)產(chǎn)品族中的所有對(duì)象時(shí)韵丑,抽象工廠模式比工廠方法模式更為簡單、更有效率洼滚,如使用工廠方法模式蒜埋,上圖所示結(jié)構(gòu)需要提供15個(gè)具體工廠该贾,而使用抽象工廠模式只需要提供3個(gè)具體工廠坑赡。
當(dāng)增加新的產(chǎn)品族的時(shí)候跑芳,符合“開閉原則”,只需讓產(chǎn)品繼承相應(yīng)的抽象產(chǎn)品猜欺,對(duì)象的工廠繼承抽象工廠即可,而無需修改其他的代碼。
當(dāng)增加產(chǎn)品等級(jí)結(jié)構(gòu)的時(shí)候值桩,不符合“開閉原則”,如新添加大眾豪椿,那么在soprt奔坟,suv,business三個(gè)具體工廠里面都進(jìn)行修改搭盾。當(dāng)然我們可以配合反射機(jī)制來對(duì)抽象工廠進(jìn)行優(yōu)化咳秉。
//根據(jù)字符串來創(chuàng)建類
NSClassFromString(<#NSString * _Nonnull aClassName#>)```
----
###總結(jié)
簡單工廠啟示是工廠方法的一種極端實(shí)現(xiàn),工廠方法是抽象方法的一種極端實(shí)現(xiàn)鸯隅。在實(shí)際項(xiàng)目中澜建,如果不是項(xiàng)目過大或者功能過于復(fù)雜,抽象工廠設(shè)計(jì)模式一般使用不到蝌以。簡單工廠模式反而是用的比較頻繁炕舵。但是這種思想我們還是需要借鑒的。在CoCoa Touch框架中的'類簇'便是基于抽象工廠模式設(shè)計(jì)跟畅。NSNumber就是最好的例子咽筋。
NSNumber *boolNumber = [NSNumber numberWithBool:YES];
NSLog(@"%@",[[boolNumber class] description]);
// 輸出 __NSCFBoolean
NSLog(@"%d",[boolNumber boolValue]);
//輸出1
NSNumber(抽象工廠)->NSCFBoolean(具體工廠子類)-> 重載boolValue工廠方法 ->返回實(shí)際產(chǎn)品
這種設(shè)計(jì)多類型的對(duì)象的創(chuàng)建。好的模式應(yīng)該是變成一種抽象徊件,不暴露創(chuàng)建過程中任何不必要的細(xì)節(jié)和創(chuàng)建對(duì)象的具體類型奸攻。
ps:最后廠長去打lol了
都看到最后了還不給個(gè)喜歡么……
[demo](https://github.com/Xmanzn/Design-Patterns)