概述
我們知道簡單工廠模式的優點是去除了客戶端與具體產品的依賴,缺點是違反了“開放-關閉原則”;工廠方法模式克服了簡單工廠模式的缺點,將產品的創建工作放到具體的工廠類,每個工廠類負責生成一個產品。但是在實際應用中,一個工廠類只創建單個產品的情況很少,一般一個工廠類會負責創建一系列相關的產品,如果我們要設計這樣的系統,工廠方法模式顯然不能滿足應用的需求,本章要介紹的抽象工廠模式,可以很好地解決一系列產品創建的問題。
定義
“提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類。”
最初的定義出現于《設計模式》(addison-wesley,1994)。
結構圖
先對上面結構圖的幾個角色進行說明:
abstractfactory:抽象工廠接口,里面應該包含所有產品創建的抽象方法;
concretefactory1和concretefactory2:具體的工廠,創建具有特定實現的產品對象;
abstractproducta和abstractproductb:抽象產品,它們可能有多種不同的實現方式;
producta1、producta2、productb1和productb2:具體的產品,是抽象產品的具體實現。
從結構圖中可以看到,抽象工廠方法最大的好處是能夠很方便的變換產品系列(例如id<abstractfactory> factory =[ [concretefactory1 alloc] init],只需要將concretefactory1換成concretefactory2,就可以創建producta2和productb2)。另外,抽象工廠方法讓具體的創建實例過程與客戶端分離,客戶端是通過它們的抽象接口操作實例,產品的具體類名也被具體工廠的實現分離,不會出現在客戶代碼中(例如id<abstractproducta> product = [factory createproducta],客戶端根本不知道具體的類名是producta1還是producta2)。
但是,抽象工廠方法也是存在缺點的,比如說現在我們要增加一個新的產品,首先,我們需要增加三個類:abstractproductc、productc1、productc2;另外,我們還需要更改三個類:abstractfactory、concretefactory1、concretefactory2,這樣,很明顯是違背“開放-關閉原則”。這也是可以理解的,沒有任何一個設計模式是完美沒有瑕疵的,這就好比世界上沒有打不敗的武功一樣。我們可以做的就是在實際的需求中,盡可能的將變化點進行隔離,以達到變化發生的時候,對整個系統的影響最小,變化所帶來的變更和成本最低。
示例
先給大家看一下數據庫訪問的類結構圖吧。
好的,簡單分析一下上面這張類結構圖,這張圖中有三個獨立的模塊兒,一個是ifactory接口,以不同數據庫為劃分原則對部門進行抽象,一個是對訪問數據庫的不同部門,還有一個是對數據庫操作的人員進行了抽象。類圖中沒有提到接下來需要給大家展示的兩個類,一個是user類,一個是department類,因為這兩個類是對數據庫數據的封裝,和結構并沒有直接關系,所以沒有顯示出來,在此說明一下,以免大家引起混亂。其實,靜下心來細細的看,結構還是蠻清晰的。
呵呵,下面還是老樣子,給大家展示一下代碼。
注意:本文所有代碼均在arc環境下編譯通過。
user類接口
#import <foundation/foundation.h>
@interface user :nsobject
@property int *id;
@property nsstring *name;
@end
user類實現
#import "user.h"
@implementation user
@synthesize name =_name;
@synthesize id =_id;
@end
department類接口
#import <foundation/foundation.h>
@interface department:nsobject
@property int *id;
@property nsstring *deptname;
@end
department類實現
#import "department.h"
@implementation department
@synthesize id =_id;
@synthesize deptname =_deptname;
@end
idepartment類接口
#import <foundation/foundation.h>
@class department;
@interface idepartment :nsobject
-(void)insert:(department*)department;
-(department*)getdepartment:(int)myid;
@end
idepartment類實現
#import "idepartment.h"
#import "department.h"
@implementation idepartment
-(void)insert:(department *)department{
return;
}
-(department*)getdepartment:(int)myid{
return nil;
}
@end
sqlserverdepartment類接口
#import "idepartment.h"
@interface sqlserverdepartment:idepartment
@end
sqlserverdepartment類實現
#import "sqlserverdepartment.h"
@implementation sqlserverdepartment
-(void)insert:(department *)department{
nslog(@"在sql server中給department表增加一條記錄");
}
-(department*)getdepartment:(int)myid{
nslog(@"在sql server中根據id得到department表一條記錄");
return nil;
}
@end
accessdepartment類接口
#import "idepartment.h"
@interface accessdepartment:idepartment
@end
*accessdepartment類實現
#import "accessdepartment.h"
@implementation accessdepartment
-(void)insert:(department *)department{
nslog(@"在access中給department表增加一條記錄");
}
-(department*)getdepartment:(int)myid{
nslog(@"在access中根據myid得到department表一條記錄");
return nil;
}
@end
iuser類接口
#import <foundation/foundation.h>
@class user;
@interfaceiuser :nsobject
-(void)insert:(user*)user;
-(user*)getuser:(int)myid;
@end
iuser類實現
#import "iuser.h"
#import "user.h"
@implementation iuser
-(void)insert:(user *)user{
return;
}
-(user*)getuser:(int)myid{
return nil;
}
@end
sqlserveruser類接口
#import "iuser.h"
@interface sqlserveruser :iuser
@end
sqlserveruser類實現
#import "sqlserveruser.h"
@implementation sqlserveruser
-(void)insert:(user *)user{
nslog(@"在sql server中給user表增加一條記錄");
}
-(user*)getuser:(int)myid{
nslog(@"在sql server中根據myid得到user表一條記錄");
return nil;
}
@end
accessuser類接口
#import "iuser.h"
@interface accessuser :iuser
@end
accessuser類實現
#import "accessuser.h"
@implementation accessuser
-(void)insert:(user *)user{
nslog(@"在access中給user表增加一條記錄");
}
-(user*)getuser:(int)myid{
nslog(@"在access中根據myid得到user表一條記錄");
return nil;
}
@end
ifactories類接口
#import "accessuser.h"
@implementation accessuser
-(void)insert:(user *)user{
nslog(@"在access中給user表增加一條記錄");
}
-(user*)getuser:(int)myid{
nslog(@"在access中根據myid得到user表一條記錄");
return nil;
}
@end
ifactories類實現
#import "ifactories.h"
#import "iuser.h"
#import "idepartment.h"
@implementation ifactories
-(iuser*)createuser{
return nil;
}
-(idepartment*)createdepartment{
return nil;
}
@end
accessfactory類接口
#import "ifactories.h"
@interface accessfactory :ifactories
@end
accessfactory類實現
#import "accessfactory.h"
#import "accessuser.h"
#import "accessdepartment.h"
@implementation accessfactory
-(iuser*)createuser{
return [[accessuser alloc]init];
}
-(idepartment*)createdepartment{
return [[accessdepartment alloc]init];
}
@end
sqlserverfactory類接口
#import "ifactories.h"
@interface sqlserverfactory :ifactories
@end
sqlserverfactory類實現
#import "sqlserverfactory.h"
#import "sqlserveruser.h"
#import "sqlserverdepartment.h"
@implementation sqlserverfactory
-(iuser*)createuser{
return [[sqlserveruser alloc]init];
}
-(idepartment*)createdepartment{
return [[sqlserverdepartment alloc]init];
}
@end
main方法調用
#import <foundation/foundation.h>
#import "user.h"
#import "department.h"
#import "ifactories.h"
#import "accessfactory.h"
#import "iuser.h"
#import "idepartment.h"
int main (int argc,const char * argv[])
{
@autoreleasepool{
user *user = [[user alloc]init];
department *dept = [[department alloc]init];
ifactories *factories = [[accessfactory alloc]init];
iuser *iu = [factories createuser];
[iu insert:user];
[iu getuser:1];
idepartment *myid = [factories createdepartment];
[myid insert:dept];
[myid getdepartment:1];
}
return 0;
}
上面羅列了一堆代碼,其實,羅列這些代碼的目的只有一個,就是為了幫助像我一樣基礎不太好的同學盡快入門,有一個感性的認識,邁過第一道門檻。