前言
本文csdn地址:http://blog.csdn.net/game3108/article/details/51147953
設(shè)計(jì)模式在工作中經(jīng)常會用到:
- 創(chuàng)建型模式(5):工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
- 結(jié)構(gòu)型模式(7):適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
- 行為型模式(11):策略模式、模板方法模式、觀察者模式、迭代子模式、責(zé)任鏈模式、命令模式、備忘錄模式、狀態(tài)模式、訪問者模式、中介者模式、解釋器模式。
本身設(shè)計(jì)模式的誕生,也是基于設(shè)計(jì)模式的六大原則:
- 單一職責(zé)原則(Single Responsibility Principle)
- 里氏替換原則(Liskov Substitution Principle)
- 依賴倒置原則(Dependence Inversion Principle)
- 接口隔離原則(Interface Segregation Principle)
- 迪米特法則(Law Of Demeter)
- 開閉原則(Open Close Principle)
具體這六大原則的含義,可以參考設(shè)計(jì)模式六大原則。
我自己在用設(shè)計(jì)模式的過程當(dāng)中,主要感覺到其實(shí)設(shè)計(jì)模式有以下作用:
- 更方便模塊的復(fù)用和測試
- 方便看懂和修改另一個寫的代碼!
本文主要以代碼形式實(shí)現(xiàn)每一種設(shè)計(jì)模式,算是自己的一種復(fù)習(xí)和實(shí)踐。相應(yīng)的代碼,也會放到github上。
本文的類圖均來自于《Objective-C編程之道 iOS設(shè)計(jì)模式解析》。
本篇主要講:
- 簡單工廠
- 工廠方法
- 抽象工廠
0.簡單工廠
簡單工廠本身并不是23種設(shè)計(jì)模式的一種,更比較像一種編程習(xí)慣,但也是經(jīng)常使用。
《Head First》的例子:
客戶到pizza store點(diǎn)不同類型的pizza,有cheese的,也有clam的。
pizza類:
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, PizzaType){
Cheese = 0,
Clam = 1
};
@interface SFPizza : NSObject
- (void) prepare;
- (void) bake;
- (void) cut;
- (void) box;
@end
#import "SFPizza.h"
@interface SFCheesePizza : SFPizza
@end
@interface SFClamPizza : SFPizza
@end
Simple Factory:
#import <Foundation/Foundation.h>
#import "SFPizza.h"
@interface SFPizzaSimpleFactory : NSObject
- (SFPizza *) createPizza:(PizzaType) pizzaType;
@end
#import "SFPizzaSimpleFactory.h"
#import "SFCheesePizza.h"
#import "SFClamPizza.h"
@implementation SFPizzaSimpleFactory
- (SFPizza *) createPizza:(PizzaType) pizzaType{
SFPizza *pizza = nil;
if (pizzaType == Cheese){
pizza = [[SFCheesePizza alloc]init];
}else if (pizzaType == Clam){
pizza = [[SFClamPizza alloc]init];
}
return pizza;
}
@end
Pizza Store:
#import <Foundation/Foundation.h>
#import "SFPizza.h"
@interface SFPizzaStore : NSObject
- (SFPizza *) orderPizza:(PizzaType)pizzaType;
@end
#import "SFPizzaStore.h"
#import "SFPizzaSimpleFactory.h"
@interface SFPizzaStore(){
SFPizzaSimpleFactory *_simpleFactory;
}
@end
@implementation SFPizzaStore
- (instancetype)init{
self = [super init];
if ( self ){
_simpleFactory = [[SFPizzaSimpleFactory alloc]init];
}
return self;
}
- (SFPizza *) orderPizza:(PizzaType)pizzaType{
SFPizza *pizza = [_simpleFactory createPizza:pizzaType];
[pizza prepare];
[pizza bake];
[pizza cut];
[pizza box];
return pizza;
}
@end
1.工廠方法
概念:定義創(chuàng)建對象的接口,讓子類決定實(shí)例化哪一個類。工廠方法使得一個類的實(shí)例化延遲到子類。
類圖:

何時使用:
- 編譯時無法準(zhǔn)備預(yù)期要創(chuàng)建的對象的類
- 類想讓其子類決定在運(yùn)行時創(chuàng)建什么
- 類有若干輔助類為子類,而你想將返回哪個子類這一信息局部化
《Head First》的例子:
紐約和芝加哥的pizza store有各自差異化的風(fēng)味,提供當(dāng)?shù)仫L(fēng)格的cheese和clam的pizza。
pizza類:
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, PizzaType){
Cheese = 0,
Clam = 1
};
@interface FMPizza : NSObject
- (void) prepare;
- (void) bake;
- (void) cut;
- (void) box;
@end
#import "FMPizza.h"
@interface FMNYCheesePizza : FMPizza
@end
@interface FMNYClamPizza : FMPizza
@end
@interface FMChicagoCheesePizza : FMPizza
@end
@interface FMChicagoClamPizza : FMPizza
@end
pizza store抽象:
#import <Foundation/Foundation.h>
#import "FMPizza.h"
@protocol FMPizzaStore <NSObject>
- (FMPizza *) createPizza:(PizzaType)pizzaType;
- (FMPizza *) orderPizza:(PizzaType)pizzaType;
@end
pizza store實(shí)現(xiàn):
#import <Foundation/Foundation.h>
#import "FMPizzaStore.h"
@interface FMNYPizzaStore : NSObject<FMPizzaStore>
@end
#import "FMNYPizzaStore.h"
#import "FMNYCheesePizza.h"
#import "FMNYClamPizza.h"
@implementation FMNYPizzaStore
- (FMPizza *) createPizza:(PizzaType)pizzaType{
FMPizza *pizza = nil;
if (pizzaType == Cheese){
pizza = [[FMNYCheesePizza alloc]init];
} else if (pizzaType == Clam){
pizza = [[FMNYClamPizza alloc]init];
}
return pizza;
}
- (FMPizza *) orderPizza:(PizzaType)pizzaType{
FMPizza *pizza = [self createPizza:pizzaType];
[pizza prepare];
[pizza bake];
[pizza cut];
[pizza box];
return pizza;
}
@end
#import <Foundation/Foundation.h>
#import "FMPizzaStore.h"
@interface FMChicagoPizzaStore : NSObject<FMPizzaStore>
@end
#import "FMChicagoPizzaStore.h"
#import "FMChicagoCheesePizza.h"
#import "FMChicagoClamPizza.h"
@implementation FMChicagoPizzaStore
- (FMPizza *) createPizza:(PizzaType)pizzaType{
FMPizza *pizza = nil;
if (pizzaType == Cheese){
pizza = [[FMChicagoCheesePizza alloc]init];
} else if (pizzaType == Clam){
pizza = [[FMChicagoClamPizza alloc]init];
}
return pizza;
}
- (FMPizza *) orderPizza:(PizzaType)pizzaType{
FMPizza *pizza = [self createPizza:pizzaType];
[pizza prepare];
[pizza bake];
[pizza cut];
[pizza box];
return pizza;
}
@end
2.抽象工廠
概念:提供一個創(chuàng)建一系列相關(guān)或相互以來對象的接口,而無需指定它們的具體的類。
類圖:

何時使用:
- 系統(tǒng)需要屏蔽有關(guān)對象如何創(chuàng)建,如何組織和如何表達(dá)
- 系統(tǒng)需要由關(guān)聯(lián)的多個對象來構(gòu)成
- 有關(guān)聯(lián)的多個對象需要一起應(yīng)用并且它們的約束是強(qiáng)迫的(不可分離)。
- 你想提供一組對象而不顯示它們的實(shí)現(xiàn)過程,只顯示它們的接口。
抽象工廠和工廠方法的區(qū)別:
抽象工廠:
- 通過對象組合創(chuàng)建抽象產(chǎn)品
- 創(chuàng)建多系列產(chǎn)品
- 必須修改父類的接口才能支持新的產(chǎn)品
工廠方法:
- 通過類繼承創(chuàng)建抽象產(chǎn)品
- 創(chuàng)建一種產(chǎn)品
- 子類化創(chuàng)建者并重載工廠方法以創(chuàng)建新的產(chǎn)品
《Head First》的例子:
紐約和芝加哥的pizza store提供的cheese和clam的pizza,但原料不同,做出來的pizza也不同。
原料類:
@interface AFCheese : NSObject
@end
@interface AFNYCheese : AFCheese
@end
@interface AFChicagoCheese : AFCheese
@end
@interface AFClam : NSObject
@end
@interface AFNYClam : AFClam
@end
@interface AFChicagoClam : AFClam
@end
@interface AFSauce : NSObject
@end
pizza類:
#import <Foundation/Foundation.h>
#import "AFCheese.h"
#import "AFClam.h"
#import "AFSauce.h"
#import "AFPizzaIngredientFactory.h"
typedef NS_ENUM(NSInteger, PizzaType){
Cheese = 0,
Clam = 1
};
@interface AFPizza : NSObject
@property (nonatomic, strong) AFCheese *cheese;
@property (nonatomic, strong) AFClam *clam;
@property (nonatomic, strong) AFSauce *sauce;
- (instancetype)initWithPizzaIngredientFactory:(id<AFPizzaIngredientFactory>) factory;
- (void) prepare;
- (void) bake;
- (void) cut;
- (void) box;
@end
#import "AFPizza.h"
@implementation AFPizza
- (instancetype)initWithPizzaIngredientFactory:(id<AFPizzaIngredientFactory>) factory{
self = [super init];
return self;
}
- (void) prepare{
}
- (void) bake{
NSLog(@"start bake");
}
- (void) cut{
NSLog(@"start cut");
}
- (void) box{
NSLog(@"start box");
}
@end
pizza 子類:
#import "AFPizza.h"
@interface AFCheesePizza : AFPizza
@end
#import "AFCheesePizza.h"
@interface AFCheesePizza(){
id<AFPizzaIngredientFactory> _factory;
}
@end
@implementation AFCheesePizza
- (instancetype)initWithPizzaIngredientFactory:(id<AFPizzaIngredientFactory>) factory{
self = [super init];
if (self){
_factory = factory;
}
return self;
}
- (void)prepare{
self.cheese = [_factory createCheese];
self.sauce = [_factory createSource];
}
@end
#import "AFPizza.h"
@interface AFClamPizza : AFPizza
@end
#import "AFClamPizza.h"
@interface AFClamPizza(){
id<AFPizzaIngredientFactory> _factory;
}
@end
@implementation AFClamPizza
- (instancetype)initWithPizzaIngredientFactory:(id<AFPizzaIngredientFactory>) factory{
self = [super init];
if (self){
_factory = factory;
}
return self;
}
- (void)prepare{
self.clam = [_factory createClam];
self.sauce = [_factory createSource];
}
@end
pizza ingredient factory 抽象
#import <Foundation/Foundation.h>
@class AFCheese;
@class AFClam;
@class AFSauce;
@protocol AFPizzaIngredientFactory
- (AFCheese *) createCheese;
- (AFClam *) createClam;
- (AFSauce *) createSource;
@end
pizza ingredient factory 實(shí)現(xiàn)
#import <Foundation/Foundation.h>
#import "AFPizzaIngredientFactory.h"
@interface AFNYPizzaIngredientFactory : NSObject<AFPizzaIngredientFactory>
@end
#import "AFNYPizzaIngredientFactory.h"
#import "AFNYCheese.h"
#import "AFNYClam.h"
#import "AFSauce.h"
@implementation AFNYPizzaIngredientFactory
- (AFCheese *) createCheese{
return [[AFNYCheese alloc]init];
}
- (AFClam *) createClam{
return [[AFNYClam alloc]init];
}
- (AFSauce *) createSource{
return [[AFSauce alloc]init];
}
@end
#import <Foundation/Foundation.h>
#import "AFPizzaIngredientFactory.h"
@interface AFChicagoIngredientFactory : NSObject<AFPizzaIngredientFactory>
@end
#import "AFChicagoIngredientFactory.h"
#import "AFChicagoCheese.h"
#import "AFChicagoClam.h"
#import "AFSauce.h"
@implementation AFChicagoIngredientFactory
- (AFCheese *) createCheese{
return [[AFChicagoCheese alloc]init];
}
- (AFClam *) createClam{
return [[AFChicagoClam alloc]init];
}
- (AFSauce *) createSource{
return [[AFSauce alloc]init];
}
@end
pizza store抽象:
#import <Foundation/Foundation.h>
#import "AFPizza.h"
@protocol AFPizzaStore
- (AFPizza *) createPizza:(PizzaType)pizzaType;
- (AFPizza *) orderPizza:(PizzaType)pizzaType;
@end
pizza store實(shí)現(xiàn):
#import <Foundation/Foundation.h>
#import "AFPizzaStore.h"
@interface AFNYPizzaStore : NSObject<AFPizzaStore>
@end
#import "AFNYPizzaStore.h"
#import "AFNYPizzaIngredientFactory.h"
#import "AFCheesePizza.h"
#import "AFClamPizza.h"
@implementation AFNYPizzaStore
- (AFPizza *) createPizza:(PizzaType)pizzaType{
AFPizza *pizza = nil;
AFNYPizzaIngredientFactory *factory = [[AFNYPizzaIngredientFactory alloc]init];
if ( pizzaType == Cheese ){
pizza = [[AFCheesePizza alloc]initWithPizzaIngredientFactory:factory];
}else if ( pizzaType == Clam ){
pizza = [[AFClamPizza alloc]initWithPizzaIngredientFactory:factory];
}
return pizza;
}
- (AFPizza *) orderPizza:(PizzaType)pizzaType{
AFPizza *pizza = [self createPizza:pizzaType];
[pizza prepare];
[pizza bake];
[pizza cut];
[pizza box];
return pizza;
}
@end
#import <Foundation/Foundation.h>
#import "AFPizzaStore.h"
@interface AFChicagoPizzaStore : NSObject<AFPizzaStore>
@end
#import "AFChicagoPizzaStore.h"
#import "AFChicagoIngredientFactory.h"
#import "AFCheesePizza.h"
#import "AFClamPizza.h"
@implementation AFChicagoPizzaStore
- (AFPizza *) createPizza:(PizzaType)pizzaType{
AFPizza *pizza = nil;
AFChicagoIngredientFactory *factory = [[AFChicagoIngredientFactory alloc]init];
if ( pizzaType == Cheese ){
pizza = [[AFCheesePizza alloc]initWithPizzaIngredientFactory:factory];
}else if ( pizzaType == Clam ){
pizza = [[AFClamPizza alloc]initWithPizzaIngredientFactory:factory];
}
return pizza;
}
- (AFPizza *) orderPizza:(PizzaType)pizzaType{
AFPizza *pizza = [self createPizza:pizzaType];
[pizza prepare];
[pizza bake];
[pizza cut];
[pizza box];
return pizza;
}
@end
一些個人總結(jié)
1.什么時候會去用工廠模式?(簡單工廠,工廠方法,抽象工廠)
為了不再需要直接創(chuàng)建對象,降低代碼耦合度。對于創(chuàng)建多種具有同一系列行為的物體,使用工廠方法。對于產(chǎn)品族使用抽象工廠。
2.簡單工廠的缺點(diǎn)
簡單工廠主要違反了開閉原則:對擴(kuò)展開放,對修改關(guān)閉。添加一種對象,就要去修改簡單工廠中的獲取對象方法。
參考資料
1.《Objective-C編程之道 iOS設(shè)計(jì)模式解析》
2.《Head First設(shè)計(jì)模式》
3.設(shè)計(jì)模式六大原則
4.設(shè)計(jì)模式六大原則