我有这样的类层次结构:
MyBox | |->ImageBox |->GalleryBox |->MovieBox |-> ...
每个字符串都由像@“image-box”或@“gallery-box”这样的字符串标识来自xml块,如下所示:
<image-box><property1>value1</property1>...</image-box>
。
所以我决定创建一个工厂类,它可以为我创建给定xml块的正确对象:
[BoxFactory.h]
@interface BoxFactory {
NSMutableDictionary* stringToClassMapping;
}
+(BoxFactory)sharedBoxFactory;
-(void)registerClass:(Class)clazz withKey:(NSString*)key;
-(MyBox*)getBoxFromXml:(NSString*)xmlBlock;
@end
[.m]
#import "BoxFactory.h"
#import "MyFantasticXmlLibrary.h"
BoxFactory* gInstance=nil;
@implementation BoxFactory
+(BoxFactory*)sharedBoxFactory {
if (gInstance==nil)
gInstance=[[BoxFactory alloc]init];
return gInstance;
}
-(id)init {
self=[super init];
stringToClassMapping=[[NSMutableDictionary alloc]initWithCapacity:10];
return self;
}
-(void)registerClass:(Class)clazz withKey:(NSString*)key {
[stringToClassMapping setObject:clazz forKey:key];
}
-(MyBox*)getBoxFromXml:(NSString*)xmlBlock {
NSString* key=[MyFantasticXmlLibrary getRootNodeName:xmlBlock];
return [[[stringToClassMapping objectForKey:key]alloc]initWithXml:xmlBlock];
}
@end
现在的问题是:具体类应该在哪里调用registerClass:withKey:
方法?似乎正确的位置将在BoxFactory的init方法中,但这意味着必须为每个添加的类修改Factory,这对于大型层次结构是不可扩展的。
我真的想找到一种方法将注册调用放在具体类本身,保持更好的组织代码和更少的依赖。但是直到现在我还没有找到一种方法来在加载类时执行代码,而没有init
它的实例。
答案 0 :(得分:1)
好的,我在发布问题后5分钟发现了它,但我仍然认为它可以帮助某人,所以我会把它留在这里:
在执行开始时,在图像中加载类时,NSObject中有一个方法+(void)load
。因此,在工厂中注册类的最佳位置是具体类本身的+(void)load
方法。例如:
@implementation ImageBox
+(void)load {
[[BoxFactory sharedBoxFactory]registerClass:[ImageBox class] withKey:@"image-box"];
}
-(id)initWithXmlBlock:(NSString*)xmlBlock {
[...]
答案 1 :(得分:1)
我有一些想法:
如果您可以控制文件格式,则可以使用NSClassFromString使Objective-C类以这种方式工作。
如果存储标签的映射 - &gt;班级或班级 - &gt;在.plist中标记,您只需在启动时使用NSDictionary dictionaryWithContentsOfFile加载,而不是在代码中将其全部加载
通过类别或协议使用属性装饰类,这样您就可以在引导时查询对象模型并使用Type Introspection来发现可用的类及其标记。这避免了必须管理两件事(plist和类)并且还避免了必须更改xml(有时候是禁止的,因为它不是你的东西)。它在启动时有点沉重,但根据你的工作情况,它可能是一个很好的交易。