抽象工廠模式搏色,提供一個創(chuàng)建一系列相關(guān)或相互依賴的接口
優(yōu)點:
- 易于交換產(chǎn)品系列
- 讓具體的創(chuàng)建實例過程與客戶端分離,客戶端是通過他們的抽象接口操縱實例嗦玖,產(chǎn)品的具體類名也被具體工廠的實現(xiàn)分離,不會出現(xiàn)在客戶端代碼中
用戶類 User
///===================User.h=================
/// 用戶類
@interface User : NSObject
/// 用戶 id
@property (nonatomic, copy) NSString *userId;
/// 用戶名
@property (nonatomic, copy) NSString *username;
@end
/// ===============User.m===================
@implementation User
@end
部門類 Department
///===============Department.h===========
/// 部門類
@interface Department : NSObject
/// 部門 id
@property (nonatomic, copy) NSString *departmentId;
/// 部門名稱
@property (nonatomic, copy) NSString *departmentName;
@end
@implementation Department
@end
用于訪問用戶的接口 IUser
/// 用于訪問用戶的接口
@protocol IUser <NSObject>
/// 新增用戶
/// @param user 用戶對象
- (void)insert:(User *)user;
/// 獲取用戶
/// @param userId 用戶 id
/// @return 用戶對象
- (User *)getUser:(NSString *)userId;
@end
用于訪問 SQL Server 中的用戶 SQLServer
///==============SQLServerUser.h===========
/// 用于訪問 SQL Server 中的用戶
@interface SQLServerUser : NSObject <IUser>
@end
///==============SQLServerUser.m============
@implementation SQLServerUser
- (void)insert:(User *)user {
NSLog(@"在 SQL Server 中給 User 表增加一條記錄");
}
- (User *)getUser:(NSString *)userId {
NSLog(@"在 SQL Server 中根據(jù) userId 得到 User 表一條記錄");
return nil;
}
@end
用于訪問 Access 中的用戶AccessUser
///=============AccessUser.h==============
/// 用于訪問 Access 中的用戶
@interface AccessUser : NSObject <IUser>
@end
///=============AccessUser.m==========
@implementation AccessUser
- (void)insert:(User *)user {
NSLog(@"在 Access 中給 User 表增加一條記錄");
}
- (User *)getUser:(NSString *)userId {
NSLog(@"在 Access 中根據(jù) userId 得到 User 表一條記錄");
return nil;
}
@end
用于訪問部門的接口IDepartment
/// 用于訪問部門的接口
@protocol IDepartment <NSObject>
/// 新增部門
///
/// @param department 部門對象
- (void)insert:(Department *)department;
/// 獲取部門
///
/// @param departmentId 部門 id
///
/// @return 部門對象
- (Department *)getDepartment:(NSString *)departmentId;
@end
用于訪問 SQL Server 中的部門SQLServerDepartment
///==============SQLServerDepartment.h=========
/// 用于訪問 SQL Server 中的部門
@interface SQLServerDepartment : NSObject <IDepartment>
@end
///==============SQLServerDepartment.m=========
@implementation SQLServerDepartment
- (void)insert:(Department *)department {
NSLog(@"在 SQL Server 中給 Department 表增加一條記錄");
}
- (Department *)getDepartment:(NSString *)departmentId {
NSLog(@"在 SQL Server 中根據(jù) departmentId 得到 Department 表一條記錄");
return nil;
}
用于訪問 Access 中的部門 AccessDepartment
///=============AccessDepartment.h===========
/// 用于訪問 Access 中的部門
@interface AccessDepartment : NSObject <IDepartment>
@end
=============AccessDepartment.h===========
@implementation AccessDepartment
- (void)insert:(Department *)department {
NSLog(@"在 Access 中給 Department 表增加一條記錄");
}
- (Department *)getDepartment:(NSString *)departmentId {
NSLog(@"在 Access 中根據(jù) departmentId 得到 Department 表一條記錄");
return nil;
}
@end
抽象工廠接口IFactory.h
/// 抽象工廠接口
@protocol IFactory <NSObject>
/// 創(chuàng)建用于訪問用戶的對象
///
/// @return 用于訪問用戶的對象
- (id<IUser>)createUser;
/// 創(chuàng)建用于訪問部門的對象
///
/// @return 用于訪問部門的對象
- (id<IDepartment>)createDepartment;
@end
創(chuàng)建用于訪問 SQL Server 對象的工廠類SQLServerFactory
///==============SQLServerFactory.h============
/// 創(chuàng)建用于訪問 SQL Server 對象的工廠類
@interface SQLServerFactory : NSObject <IFactory>
@end
///==============SQLServerFactory.m============
@implementation SQLServerFactory
- (id<IUser>)createUser {
return [[SQLServerUser alloc] init];
}
- (id<IDepartment>)createDepartment {
return [[SQLServerDepartment alloc] init];
}
@end
創(chuàng)建用于訪問 Access 對象的工廠類 AccessFactory
/// ================AccessFactory.h==========
/// 創(chuàng)建用于訪問 Access 對象的工廠類
@interface AccessFactory : NSObject <IFactory>
@end
/// ================AccessFactory.m==========
@implementation AccessFactory
- (id<IUser>)createUser {
return [[AccessUser alloc] init];
}
- (id<IDepartment>)createDepartment {
return [[AccessDepartment alloc] init];
}
@end
類圖
AbstractProductA 和 AbstractProductB 是兩個抽象產(chǎn)品, 只定義了接口谴麦,可以有不同的實現(xiàn)方式, 先相當于User 和 Department, ProductA1狭瞎、 ProductA2细移、 ProductB1 ProductB2就是對兩個抽象產(chǎn)品的實現(xiàn)
同理, IFactory 是一個抽象接口熊锭,它里面應(yīng)該包含所有產(chǎn)品的創(chuàng)建的抽象方法, ConcreteFactory1 ConcreteFactory2 就是具體工廠
通常實在運行時刻再創(chuàng)建一個ConcreteFactory類的實例弧轧,這個具體的工廠再創(chuàng)建具有特定實現(xiàn)的產(chǎn)品對象, 也就是說碗殷, 為創(chuàng)建不同的產(chǎn)品對象精绎,客戶端使用不同的具體工廠
抽象工廠與工廠方法比較
抽象工廠 | 工廠方法 |
---|---|
通過對象組合創(chuàng)建抽象產(chǎn)品 | 通過類繼承創(chuàng)建抽象產(chǎn)品 |
創(chuàng)建多系列產(chǎn)品 | 創(chuàng)建一種產(chǎn)品 |
必須修改父類接口才能支持新的產(chǎn)品 | 子類化創(chuàng)建者并重載工廠方法以創(chuàng)建新產(chǎn)品 |
iOS中的抽象工廠
在iOS中,有很多基礎(chǔ)類采用了這一模式锌妻,常見的就是NSNumber
代乃。創(chuàng)建NSNumber實例的方法完全符合抽象工廠模式
NSNumber *boolNumber = [NSNumber numberWithBool:YES];
NSNumber *charNumber = [NSNumber numberWithChar:'a'];
NSNumber *intNumber = [NSNumber numberWithInt:1];
NSNumber *floatNumber = [NSNumber numberWithFloat:1.0];
NSNumber *doubleNumber = [NSNumber numberWithDouble:1.0];
接受不同類型的參數(shù)并返回NSNumber實例的類方法是類工廠方法(工廠模式)。NSNumber
的類工廠方法生產(chǎn)各種數(shù)工廠。numberWithBool:
創(chuàng)建NSCFBoolean
工廠的實例搁吓,而numberWithInt:
創(chuàng)建NSCFNumber
的實例原茅。NSNumber
中的類工廠方法定義了決定實例化何種私有具體子類(比
如,NSCFBoolean
或NSCFNumber
)的默認行為堕仔。這一版本的工廠方法是傳統(tǒng)工廠方法模式的一個變體擂橘,此處的抽象產(chǎn)品為作為工廠的具體
NSNumber
子類。NSNumber
是抽象工廠實現(xiàn)的一個例子摩骨⊥ㄕ辏基礎(chǔ)框架中抽象工廠的此種特點被稱為類簇。
類簇是基礎(chǔ)框架中一種常見的設(shè)計模式恼五,基于抽象工廠模式的思想昌罩。它將若干相關(guān)的私有具體工廠子類集合到一個公有的抽象超類之下。比如灾馒,數(shù)包含了各種數(shù)值類型的完整集合茎用,如字符、浮點數(shù)你虹、整數(shù)等绘搞。這些數(shù)值類型都是數(shù)的子集。所以NSNumber
自然成為這些數(shù)子類型的超類型傅物。NSNumber
有一系列公有API夯辖,定義了各種類型的數(shù)所共有的行為《危客戶端在使用時無需知道NSNumber
實例的具體類型蒿褂。
類簇是抽象工廠的一種形式。比如卒暂,NSNumber
本身是一個高度抽象的工廠啄栓,NSCFBoolean
和NSCFNumber
是具體工廠子類。子類是具體工廠也祠,因為它們重載了NSNumber
中聲明的公有工廠方法以生產(chǎn)產(chǎn)品昙楚。
例如,intValue
和boolValue
根據(jù)實際NSNumber
對象的內(nèi)部值返回一個值诈嘿,雖然值的數(shù)據(jù)類型可能不同堪旧。從這些工廠方法返回的實際值就是抽象工廠模式的最初定義中的所說產(chǎn)品。
創(chuàng)建抽象產(chǎn)品的工廠方法與創(chuàng)建抽象工廠的工廠方法之間有個不同點奖亚。顯然淳梦,像intValue
和boolValue
這樣的工廠方法,應(yīng)該在具體工廠(NSCFNumber
與NSCFBoolean
)中重載以返回產(chǎn)品昔字。而像numberWithBool:
和numberWithInt:
這樣的工廠方法并不是為了返回產(chǎn)品爆袍,而是為了返回能返回產(chǎn)品的工廠,因此它們不應(yīng)在具體子類重載。
總結(jié)
抽象工廠是一種常見的設(shè)計模式陨囊。它是最基本的弦疮,因為它可以設(shè)計許多類型的對象創(chuàng)建。一系列相關(guān)類好的設(shè)計模式谆扎,應(yīng)該作為一種抽象挂捅,不為客戶端所見。抽象工廠可以順暢地提供這種抽象堂湖,而不暴露創(chuàng)建過程中任何不必要的細節(jié)或所創(chuàng)建對象的確切類型。