類工廠方法是什么?ios面試攻克篇(五)


'寫在前面的話'
這些是我對iOS面試時會碰到的問題的解決方法,整理出來分享給大家,有些錯誤不要
笑了,希望對大家有所幫助。大家有更好的解決辦法也歡迎溝通交流。
一直以來都有寫點兒東西的想法,就從筆記、從閱讀開始吧,加油!'


基礎概念

類工廠方法的實現是為了向客戶提供方便,它們將分配和初始化合在一個步驟中,返回被創建的對象,并 進行自動釋放處理。這些方法的形式是+ (type)className...其中 className不包括任何前綴)。 工廠方法可能不僅僅為了方便使用。它們不但可以將分配和初始化合在一起,還可以為初始化過程提供對 象的分配信息。

  • 工廠方法:定義創建對象的借口,讓子類決定實例化哪一個類。工廠方法是一個類的實例化延遲到了子類
  • 例如 :Shoes廠有兩個子類(Newbalance、Nike)構建類圖如下:
列如

1. 簡單工廠模式

如何理解簡單工廠,工廠方法, 抽象工廠三種設計模式?

簡單工廠的生活場景,賣早點的小攤販,他給你提供包子,饅頭,地溝油烙的煎餅等,小販是一個工廠,它生產包子,饅頭,地溝油烙的煎餅。該場景對應的UML圖如下所示:


簡單工廠模式的參與者:

工廠(Factory)角色:接受客戶端的請求,通過請求負責創建相應的產品對象。
抽象產品(Abstract Product)角色:是工廠模式所創建對象的父類或是共同擁有的接口。可是抽象類或接口。
具體產品(ConcreteProduct)對象:工廠模式所創建的對象都是這個角色的實例。

簡單工廠模式的演變:

  • 當系統中只有唯一的產品時,可以省略抽象產品,如圖1所示。這樣,工廠角色與具體產品可以合并。

簡單工廠模式的優缺點:

  • 工廠類含有必要的創建何種產品的邏輯,這樣客戶端只需要請求需要的產品,而不需要理會產品的實現細節。
  • 工廠類只有一個,它集中了所有產品創建的邏輯,它將是整個系統的瓶頸,同時造成系統難以拓展。
  • 簡單工廠模式通常使用靜態工廠方法,這使得工廠類無法由子類繼承,這使得工廠角色無法形成基于繼承的等級結構。

下面編寫了一個賣早餐的例子來說明:

SFFactory.h 作為工廠的角色 #import "SFOperation.h"typedef NS_ENUM(NSInteger, SFFactoryProductType){    SFFactoryProductTypeMantou,    SFFactoryProductTypeYoutiao,};@interface SFFactory : NSObject//工廠(Factory)角色:接受客戶端的請求,通過請求負責創建相應的產品對象。+ (SFOperation *)operationBreakfast:(SFFactoryProductType )breakfastType; @end
SFFactory.m #import "SFOperationMantou.h"#import "SFOperationYoutiao.h"@implementation SFFactory+ (SFOperation *)operationBreakfast:(SFFactoryProductType)breakfastType{    //通過枚舉返回不同的產品    SFOperation *operation;    switch (breakfastType) {        case SFFactoryProductTypeMantou:            operation = [[SFOperationMantou alloc] init];            break;        case SFFactoryProductTypeYoutiao:            operation = [[SFOperationYoutiao alloc] init];            break;        default:            return nil;            break;    }    return operation;} @end
SFOperation.h 抽象產品角色,通過子類化它來獲得具體的角色 @interface SFOperation : NSObject@property (nonatomic, copy, readonly)NSString *product;- (void)productBreakfast; @end 
SFOperation.m @implementation SFOperation- (void)productBreakfast{    }@end
SFOperationMantou.h  具體產品角色,SFOperation的子類化,實際工廠返回的可能就是它,當然,也可能是油條、豆漿等 @interface SFOperationMantou : SFOperation- (void)productBreakfast;@end
SFOperationMantou.m @synthesize product = _product;- (void)productBreakfast{    _product = @"饅頭";}

最后是main函數的調用

SFOperation *sfOperation = [SFFactory operationBreakfast:SFFactoryProductTypeMantou];[sfOperation productBreakfast];NSLog(@"生產產品:%@",sfOperation.product);

SFFactory作為一個工廠,里面包含了創建產品的邏輯,這里使用一個枚舉來控制是創建油條還是饅頭的具體產品。但是這里的問題就是,如果產品類的邏輯非常復雜,那么這個共產類會復雜的不可控。當然,外部調用的話,根本無需關心內部如何創建具體的產品,因為抽象產品類SFOperation已經制定了一套接口規范。

簡潔來說:抽象工廠直接 -- (創建) --> 具體產品 (這里沒有具體工廠的概念 但是有抽象產品的概念)

2. 工廠方法模式

工廠方法使用OOP的多態性,將工廠和產品都抽象出一個基類,在基類中定義統一的接口,然后在具體的工廠中創建具體的產品。工廠方法的生活場景,聯合利華要生產“夏士蓮”和“清揚”兩款洗發水,它會建一個生產“夏士蓮”的工廠和一個生產“清揚”的工廠。

工廠方法模式中的參與者:

抽象工廠角色:與應用程序無關,任何在模式中創建對象的工廠必須實現這個接口。
具體工廠角色:實現了抽象工廠接口的具體類,含有與引用密切相關的邏輯,并且受到應用程序的調用以創建產品對象。
抽象產品角色:工廠方法所創建產品對象的超類型,也就是產品對象的共同父類或共同擁有的接口。
具體產品角色:這個角色實現了抽象產品角色所聲名的接口。工廠方法所創建的每個具體產品對象都是某個具體產品角色的實例。

工廠方法的優缺點:

  • 降低了工廠類的內聚,滿足了類之間的層次關系,又很好的符合了面向對象設計中的單一職責原則,這樣有利于程序的拓展,如圖三所示:

總結:把“共性”提取出來,根據各自的“個性”建立各自的繼承共性的實現。下面依然使用早餐的例子來說明:

FFactory.h  //抽象工廠角色 @interface FFactory : NSObject+ (FFOperation *)createOperation;@end
FFactory.m @implementation FFactory+ (FFOperation *)createOperation{    FFOperation *operation = [[FFOperation alloc] init];    return operation;}@end
FFOperation.h 抽象產品角色 @interface FFOperation : NSObject@property (nonatomic, copy, readonly)NSString *product;- (void)productBreakfast;@end
FFOperation.m @implementation FFOperation- (void)productBreakfast{    }@end
FFactoryMantou.h 具體工廠角色 @interface FFactoryMantou : FFactory@end
FFactoryMantou.m #import "FFOperationMantou.h"@implementation FFactoryMantou+ (FFOperation *)createOperation{    return [[FFOperationMantou alloc] init];}@end
FFOperationMantou.h 具體產品角色 @interface FFOperationMantou : FFOperation- (void)productBreakfast;@end
FFOperationMantou.m @synthesize product = _product;- (void)productBreakfast{    _product = @"饅頭";}

main里面的調用

FFOperation *ffOperation = [FFactoryMantou createOperation];[ffOperation productBreakfast];NSLog(@"生產產品:%@",ffOperation.product);

與簡單工廠模式把所有產品都放到SFFactory來獲取相比,工廠模式每次需要一個新的產品,就需要新建一個具體工廠來生成新的產品。當你需要豆漿的時候,只要新建一個繼承與FFactory的工廠類,再創建一個繼承于FFOperation的具體產品就可以創建新的產品了。對原來的代碼都不需要做任何修改。這就使得產品的拓展變得簡單。

簡潔來說:具體工廠直接 -- (創建) --> 具體產品 (這里多了一個具體工廠的概念,但是只是繼承關系,過多的沒有用上)

3. 抽象工廠設計模式

所謂抽象工廠是指一個工廠等級結構可以創建出分屬于不同產品等級結構的一個產品族中的所有對象,以創建Unix控件和Windows控件為例說明,我們需要一個抽象工廠下面有兩個子工廠,一個叫做UnixFactory,用于生產Unix族控件,一個叫做WinFactory,用于生產Win族控件。抽象工廠與工廠方法的區別是,工廠方法中的具體工廠一般只生產一個或幾個控件對象,而抽象工廠中的具體工廠生產的是一族控件對象。如圖4所示。

抽象工廠中的參與者:

抽象工廠(Abstract Factory)角色:擔任這個角色的是工廠方法模式的核心,它是與應用系統商業邏輯無關的。
具體工廠(Concrete Factory)角色:這個角色直接在客戶端的調用下創建產品的實例。這個角色含有選擇合適的產品對象的邏輯,而這個邏輯是與應用系統的商業邏輯緊密相關的。
抽象產品(Abstract Product)角色:擔任這個角色的類是工廠方法模式所創建的對象的父類,或它們共同擁有的接口。
具體產品(Concrete Product)角色:抽象工廠模式所創建的任何產品對象都是某一個具體產品類的實例。這是客戶端最終需要的東西,其內部一定充滿了應用系統的商業邏輯。

抽象工廠的使用場景:

  • 一個系統不應當依賴于產品類實例如何被創建、組合和表達的細節,這對于所有形態的工廠模式都是重要的。
  • 這個系統有多于一個的產品族,而系統只消費其中某一產品族。
    同屬于同一個產品族的產品是在一起使用的,這一約束必須在系統的設計中體現出來。
  • 系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴于實現。

抽象工廠模式與工廠方法模式的區別:

工廠方法模式:每個抽象產品派生多個具體產品類,每個抽象工廠類派生多個具體工廠類,每個具體工廠類負責一個具體產品的實例創建;
抽象工廠模式:每個抽象產品派生多個具體產品類,每個抽象工廠派生多個具體工廠類,每個具體工廠負責多個(一系列)具體產品的實例創建。

一樣的,下面使用早餐店來舉例:

AFFactory.h 抽象工廠角色
 #import "AFOperation.h"@interface AFFactory : NSObjecttypedef NS_ENUM(NSInteger, AFFactoryProductType)
{    AFFactoryProductTypeMantou,    AFFactoryProductTypeYoutiao,};
+ (instancetype)factoryWithType:(AFFactoryProductType)type;- (AFOperation *)createProduct;
#import "AFFactoryMantou.h"#import "AFFactoryYoutiao.h"@implementation AFFactory+ (instancetype)factoryWithType:
(AFFactoryProductType)type{    AFFactory *factory;    switch (type) {        
case AFFactoryProductTypeMantou:   
         factory = [[AFFactoryMantou alloc] init];         
   break;    
    case AFFactoryProductTypeYoutiao:      
      factory = [[AFFactoryYoutiao alloc] init];    
        break;     
  default:          
  break;    }    
return factory;}- (AFOperation *)createProduct{    return nil;}@end
AFOperation.h 抽象產品角色 
@interface AFOperation : 
NSObject@property 
(nonatomic, copy, readonly)NSString *product;
- (void)productBreakfast;@end
@implementation AFOperation- (void)productBreakfast{}@end
AFFactoryMantou.h 具體工廠角色 
@interface AFFactoryMantou : AFFactory@end
AFFactoryMantou.m
 #import "AFOperationMantou.h"@implementation AFFactoryMantou- (AFOperation *)
createProduct{    
return [[AFOperationMantou alloc] init];
}@end
@interface AFOperationMantou : AFOperation@end
@implementation AFOperationMantou@synthesize product = _product;
- (void)productBreakfast{    _product = @"饅頭";
}@end

main函數調用

AFFactory *afFactory = [AFFactory factoryWithType:
AFFactoryProductTypeMantou];AFOperation *afOperation = [afFactory createProduct];[afOperation productBreakfast];
NSLog(@"生產產品;%@",afOperation.product);

使用AFFacytory來創建工廠,屏蔽了內部的實現,你可以不用管內部是使用的饅頭工廠還是油條工廠。你需要關注的就是他們公有的接口就行了。抽象工廠的最大好處在于,讓你感覺不到內部差異性。cocoa框架里到處都是使用了這種設計。比如NSString、NSNumber。(這方面可以查閱cocoa的類簇這個概念來了解相關資料)當然,缺點就是,如果你修改了抽象類的方法,那么所有的子類都要跟著一起修改。

簡潔來說:抽象工廠直接 -- (創建) --> 具體工廠 --(創建)--> 具體產品 (這里是上面的更深一步,把抽象工廠的作用變大,多層,在外層調用抽象類,根本不用知道里面是什么)

總結:從簡單工廠模式到工廠模式,再到抽象工廠模式。可以看到整個模式的一步步演進。簡單工廠模式在產品多樣之后,整個工廠將會變得臃腫而難以維護。于是我們將簡單工廠模式中的工程做了抽象處理,這樣每種產品對應一個工廠。這樣無疑會增加代碼量。但是好處是顯而易見的,單獨讓一個工廠處理一種產品會讓邏輯變得好維護。但是這樣還不夠,因為增加新的品類,就會產生新的類,對于調用者來說,處理太多具有相同接口的類顯然是不合算的。于是,我們使用抽象工廠模式來解決這個問題。我們讓抽象工廠內部做一個封裝,用以隱藏真正的具體工廠。這樣,對于調用者來說,即時內部增加了新的產品,你也是不知道的。

原文轉載:http://www.lxweimin.com/p/847af218b1f0

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容