我担心这是一个相当简单的问题,但经过大量的谷歌搜索后,我想我已经超出了我的预期结果。我相信我的问题与设计模式有关,但是我可能错了。
我的应用程序调用RESTful API并返回相当于NSDictionary
所代表的模型对象列表的内容。我将致电NNEntity
。 (概念上)存在多种不同的NNEntity子类型。 NNEntity
的所有子类型都共享entityID
的属性,但每个子类都有自己独特的属性。 NNEntity
的所有实例都有一个名为readFromDict:(NSDictionary *)d
的方法,用于填充各自的属性。此方法由所有NNEntity
个子类型符合的协议强制执行。它看起来像这样:
//NNEntity.h
@interface NNEntity : NSObject <NNReadFromDictProtocol>
@property (nonatomic, strong) NSString *entityID;
@end
//NNEntity.m
@implementation NNEntity
- (void)readFromDict:(NSDictionary *)d {
//set common properties from values in d
self.entityID = [d objectForKey:@"ID"];
}
@end
//NNSubEntity1.h
@interface NNSubEntity1 : NSEntity <NNReadFromDictProtocol>
@property (nonatomic, strong) NSString *favoriteColor;
@end
//NNSubEntity1.m
@implementation NNSubEntity1
- (void)readFromDict:(NSDictionary *)d {
[super readFromDict:d];
//set unique properties from values in d
self.favoriteColor = [d objectForKey:@"colorPreference]:
}
@end
//NNSubEntity2.h
@interface NNSubEntity2 : NSEntity <NNReadFromDictProtocol>
@property (nonatomic, strong) NSString *middleName;
@end
//NNSubEntity2.m
@implementation NNSubEntity2
- (void)readFromDict:(NSDictionary *)d {
[super readFromDict:d];
//set unique properties from values in d
self.middleName = [d objectForKey:@"middleName]:
}
@end
我已经阅读了有关使用Factory或Builder Desing模式的类似用例的各种内容,但我很好奇在这个相当简单的情况下是否有必要。例如,如果我打算调用类似这样的内容,我当前的代码最终是否同时创建了NNEntity
和NNSubEntity2
的实例:
NNEntity *newEntity = [[NNSubEntity2 alloc] init];
//assume dict exists already and is properly keyed
[newEntity readFromDict:dict];
我假设没有,但newEntity
是否同时具有entityID
的公共属性以及middleName
的唯一属性?此外,如果您对更好或更有效的设计方法有所了解,我们非常感谢。
答案 0 :(得分:2)
这看起来就像你应该如何做到这一点。您有一个读取公共属性的基类,以及读取其特定属性的子类。
例如,我当前的代码最终是否同时创建了NNEntity和NNSubEntity2的实例?
NNEntity *newEntity = [[NNSubEntity2 alloc] init];
不。当你运行它时,你实例化NNSubEntity2
并将结果存储在由它的超类键入的变量中,这是完全有效的。这允许您调用超类上定义的任何方法,但实际的实例仍然是子类。
肯定会的。它继承了超类中的实例变量,属性和方法。newEntity是否同时具有entityID的公共属性以及middleName的唯一属性设置?
请放心,据我所知,这看起来很合理,是我以前用过的模式。
答案 1 :(得分:1)
我是这样做的。
// NNEntity.h
@interface NNEntity : NSObject
@property (nonatomic, retain) NSString *entityId;
@end;
// NNEntity.m
@implementation NNEntity
@end;
// NNEntity+KVC.h
@interface NNEnity (KVC)
-(void)setValue:(id)value forUndefinedKey:(NSString *)key {
@end
// NNEntity+KVC.m
@implementation NNEntity (KVC)
-(void)setValue:(id)value forUndefinedKey:(NSString *)key {
// Handle this as appropriate to your app.
// A minimal implementation will throw an exception.
}
@end
同样适合您的各种子类。您(不一定)需要子类上的类别。
然后,给你NSDictionary *dict
你的东西:
NNEntity *entity = [[NNEntity alloc] init];
[entity setValuesForKeysWithDictionary:dict];
中提琴!你完成了。对这种方法有一些批评,但鉴于setValue:forUndefinedKey:
的强大实施,我认为这是安全且非常灵活的。
秘密在Apple的美丽Key-Value Coding技术中。从本质上讲,setValuesForKeysWithDictionary:
会迭代你给它的dict键,并且每次调用它的接收器setValue:forKey:
。它看起来像这样(虽然我确信Apple在引擎盖下对它进行了优化):
-(void)setValuesForKeysWithDictionary:(NSDictionary *)dictionary {
NSArray *keys = [dictionary allKeys];
for (NSString* key in keys) {
[self setValue:[dictionary valueForKey:key] forKey:key];
}
}
我也喜欢这种方法,因为转换为CoreData很简单;当你告诉CoreData“渲染”你的模型时,它只是覆盖你的存根模型类,保持你的KVC类别完好无损。更重要的是,如果您的setValue:forUndefinedKey:
实现顺利,您可以对后端进行模型更改而不会导致应用程序崩溃(这有点不可,但与您的工厂解决方案没有太大区别)。
当然,我没有解决您有选择地选择要实例化的类的需求。但这是一个更大的设计问题,甚至可能会受到API和后端设计的影响。所以我推迟。
此外,正如您在下面的评论中所述,属性名称必须匹配。对于一些开发人员来说,这是一个显示阻碍,特别是如果你无法控制后端和客户端。
试一试。欢迎提供反馈。