工厂模式
工厂模式(Factory Design Pattern)分为三种更加细分的类型:简单工厂、工厂方法和抽象工厂。
简单工厂(Simple Factory)
在代码示例中,根据配置文件的后缀(json、xml、properties),选择不同的解析器(DMJsonRuleConfigParser、DMXmlRuleConfigParser、DMPropertiesRuleConfigParser),将存储在文件中的配置解析成内存对象DMRuleConfig。
@protocol DMRuleConfigParser <NSObject>
- (DMRuleConfig *)parse:(NSString *)configStr;
@end
@interface DMJsonRuleConfigParser : NSObject <DMRuleConfigParser>
@end
@implementation DMJsonRuleConfigParser
- (DMRuleConfig *)parse:(NSString *)configStr
{
DMRuleConfig *ruleConfig = [[DMRuleConfig alloc] init];
/*
省略解析
*/
return ruleConfig;
}
@end
@interface DMXmlRuleConfigParser : NSObject <DMRuleConfigParser>
@end
@implementation DMXmlRuleConfigParser
- (DMRuleConfig *)parse:(NSString *)configStr
{
DMRuleConfig *ruleConfig = [[DMRuleConfig alloc] init];
/*
省略解析
*/
return ruleConfig;
}
@end
@interface DMPropertiesRuleConfigParser : NSObject <DMRuleConfigParser>
@end
@implementation DMPropertiesRuleConfigParser
- (DMRuleConfig *)parse:(NSString *)configStr
{
DMRuleConfig *ruleConfig = [[DMRuleConfig alloc] init];
/*
省略解析
*/
return ruleConfig;
}
@end
@implementation DMRuleConfigSource
- (void)sampleFactory
{
NSString *filePath = @"";
NSString *fileExtension = [self getFileExtension:filePath];
id<DMRuleConfigParser> parser = nil;
if ([fileExtension isEqualToString:@"json"]) {
parser = [[DMJsonRuleConfigParser alloc] init];
} else if ([fileExtension isEqualToString:@"xml"]){
parser = [[DMXmlRuleConfigParser alloc] init];
} else if ([fileExtension isEqualToString:@"properties"]) {
parser = [[DMPropertiesRuleConfigParser alloc] init];
}
NSString *fileContent = @"";
// 从配置文件中读取配置文本到fileContent中
DMRuleConfig *ruleConfig = [parser parse:fileContent];
}
/*
* 根据文件路径获取文件后缀,比如demo.json返回json
*/
- (NSString *)getFileExtension:(NSString *)filePath
{
return @"json";
}
@end
为了让代码逻辑更加清晰,可读性更好,要善于将功能独立的代码块封装成函数。可以将代码中涉及parser创建的而部分逻辑玻璃出来,抽象成- (id<DMRuleConfigParser>)createParser:(NSString *)fileExtension函数。重构之后如下
@protocol DMRuleConfigParser <NSObject>
- (DMRuleConfig *)parse:(NSString *)configStr;
@end
interface DMJsonRuleConfigParser : NSObject <DMRuleConfigParser>
@end
@implementation DMJsonRuleConfigParser
- (DMRuleConfig *)parse:(NSString *)configStr
{
DMRuleConfig *ruleConfig = [[DMRuleConfig alloc] init];
/*
省略解析
*/
return ruleConfig;
}
@end
@interface DMXmlRuleConfigParser : NSObject <DMRuleConfigParser>
@end
@implementation DMXmlRuleConfigParser
- (DMRuleConfig *)parse:(NSString *)configStr
{
DMRuleConfig *ruleConfig = [[DMRuleConfig alloc] init];
/*
省略解析
*/
return ruleConfig;
}
@end
@interface DMPropertiesRuleConfigParser : NSObject <DMRuleConfigParser>
@end
@implementation DMPropertiesRuleConfigParser
- (DMRuleConfig *)parse:(NSString *)configStr
{
DMRuleConfig *ruleConfig = [[DMRuleConfig alloc] init];
/*
省略解析
*/
return ruleConfig;
}
@end
@implementation DMRuleConfigSource
- (void)sampleFactory
{
NSString *filePath = @"";
NSString *fileExtension = [self getFileExtension:filePath];
id<DMRuleConfigParser> parser = nil;
parser = [self createParser:fileExtension];
NSString *fileContent = @"";
// 从配置文件中读取配置文本到fileContent中
DMRuleConfig *ruleConfig = [parser parse:fileContent];
}
/*
* 根据文件路径获取文件后缀,比如demo.json返回json
*/
- (NSString *)getFileExtension:(NSString *)filePath
{
return @"json";
}
- (id<DMRuleConfigParser>)createParser:(NSString *)fileExtension
{
id<DMRuleConfigParser> parser;
if ([fileExtension isEqualToString:@"json"]) {
parser = [[DMJsonRuleConfigParser alloc] init];
} else if ([fileExtension isEqualToString:@"xml"]){
parser = [[DMXmlRuleConfigParser alloc] init];
} else if ([fileExtension isEqualToString:@"properties"]) {
parser = [[DMPropertiesRuleConfigParser alloc] init];
}
return parser;
}
@end
为了让类的职责更加单一、代码更加清晰,还可以进一步将- (id<DMRuleConfigParser>)createParser:(NSString *)fileExtension 方法剥离到一个独立的类中,让这个类只负责对象的创建。这个类就是简单工厂模式类。如下:
@protocol DMRuleConfigParser <NSObject>
- (DMRuleConfig *)parse:(NSString *)configStr;
@end
interface DMJsonRuleConfigParser : NSObject <DMRuleConfigParser>
@end
@implementation DMJsonRuleConfigParser
- (DMRuleConfig *)parse:(NSString *)configStr
{
DMRuleConfig *ruleConfig = [[DMRuleConfig alloc] init];
/*
省略解析
*/
return ruleConfig;
}
@end
@interface DMXmlRuleConfigParser : NSObject <DMRuleConfigParser>
@end
@implementation DMXmlRuleConfigParser
- (DMRuleConfig *)parse:(NSString *)configStr
{
DMRuleConfig *ruleConfig = [[DMRuleConfig alloc] init];
/*
省略解析
*/
return ruleConfig;
}
@end
@interface DMPropertiesRuleConfigParser : NSObject <DMRuleConfigParser>
@end
@implementation DMPropertiesRuleConfigParser
- (DMRuleConfig *)parse:(NSString *)configStr
{
DMRuleConfig *ruleConfig = [[DMRuleConfig alloc] init];
/*
省略解析
*/
return ruleConfig;
}
@end
@interface DMRuleConfigParserFactory : NSObject
- (id<DMRuleConfigParser>)createParser:(NSString *)fileExtension;
@end
@implementation DMRuleConfigParserFactory
- (id<DMRuleConfigParser>)createParser:(NSString *)fileExtension
{
id<DMRuleConfigParser> parser;
if ([fileExtension isEqualToString:@"json"]) {
parser = [[DMJsonRuleConfigParser alloc] init];
} else if ([fileExtension isEqualToString:@"xml"]){
parser = [[DMXmlRuleConfigParser alloc] init];
} else if ([fileExtension isEqualToString:@"properties"]) {
parser = [[DMPropertiesRuleConfigParser alloc] init];
}
return parser;
}
@end
@implementation DMRuleConfigSource
- (void)sampleFactory
{
NSString *filePath = @"";
NSString *fileExtension = [self getFileExtension:filePath];
id<DMRuleConfigParser> parser = nil;
DMRuleConfigParserFactory *configParserFactory = [[DMRuleConfigParserFactory alloc] init];
parser = [configParserFactory createParser:fileExtension];
NSString *fileContent = @"";
// 从配置文件中读取配置文本到fileContent中
DMRuleConfig *ruleConfig = [parser parse:fileContent];
}
/*
* 根据文件路径获取文件后缀,比如demo.json返回json
*/
- (NSString *)getFileExtension:(NSString *)filePath
{
return @"json";
}
@end
在上面的示例代码中,每次调用DMRuleConfigParserFactory 的- (id<DMRuleConfigParser>)createParser:(NSString *)fileExtension 方法的时候,都会新创建一个parser。实际上,如果parser可以复用,为了节省内存和创建对象的时间,可以将parser事先创建好缓存起来。当调用- (id<DMRuleConfigParser>)createParser:(NSString *)fileExtension 方法的时候,直接从缓存中取出parser对象直接使用。代码如下:
static NSMutableDictionary<NSString *, id<DMRuleConfigParser>> *cachedParsers;
@implementation DMRuleConfigParserFactory
+ (void)load
{
cachedParsers = [[NSMutableDictionary<NSString *, id<DMRuleConfigParser>> alloc] init];
[cachedParsers setObject:[[DMJsonRuleConfigParser alloc] init] forKey:@"json"];
[cachedParsers setObject:[[DMXmlRuleConfigParser alloc] init] forKey:@"xml"];
[cachedParsers setObject:[[DMPropertiesRuleConfigParser alloc] init] forKey:@"properties"];
}
- (id<DMRuleConfigParser>)createParser:(NSString *)fileExtension
{
id<DMRuleConfigParser> parser;
parser = [cachedParsers objectForKey:fileExtension];
return parser;
}
@end
对于上面两种简单工厂模式的实现方法。如果要添加新的parser,势必要改动DMRuleConfigParserFactory的代码,违反开闭原则。
除此之外,在DMRuleConfigParserFactory的第一种代码实现中,有一组if分支判断逻辑,是不是应该用多态或者其它设计模式来代替呢?实际上,如果if分支不是很多,代码中有if分支也是完全可以接受的。应用多态或者设计模式来代替if分支判断逻辑,也并不是没有任何缺点的,它虽然提高了代码的扩展性,更加符合开闭原则,但也增加了类的个数,牺牲了代码的可读性。
总结一下,尽管简单工厂模式的代码实现中,有多处if分支判断逻辑,违背开闭原则,但权衡扩展性和可读性,这样的代码实现在大多数情况下(比如,不需要频繁地添加parser,也没有太多的parser)是没有问题的。
网友评论