Objective c 子类化iOS模型对象-适当的设计模式
我担心这是一个相当简单的问题,但在谷歌搜索了很多次之后,我认为我已经超出了预期的结果。我相信我的问题与设计模式有关,但唉,我可能错了 我的应用程序调用一个RESTful API并返回一个由Objective c 子类化iOS模型对象-适当的设计模式,objective-c,design-patterns,Objective C,Design Patterns,我担心这是一个相当简单的问题,但在谷歌搜索了很多次之后,我认为我已经超出了预期的结果。我相信我的问题与设计模式有关,但唉,我可能错了 我的应用程序调用一个RESTful API并返回一个由NSDictionary表示的模型对象列表。我将调用nEntity。存在(概念上)多个不同的N实体子类型。nEntity的所有子类型都共享entityID的属性,但每个子类型都有自己独特的属性。nEntity的所有实例都有一个名为readFromDict:(NSDictionary*)d的方法,该方法填充它们各
NSDictionary
表示的模型对象列表。我将调用nEntity
。存在(概念上)多个不同的N实体子类型。nEntity
的所有子类型都共享entityID
的属性,但每个子类型都有自己独特的属性。nEntity
的所有实例都有一个名为readFromDict:(NSDictionary*)d
的方法,该方法填充它们各自的属性。此方法由所有n实体
子类型都符合的协议强制执行。看起来是这样的:
//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
NNEntity *newEntity = [[NNSubEntity2 alloc] init];
//assume dict exists already and is properly keyed
[newEntity readFromDict:dict];
我假设不是,但是
newEntity
是否正确设置了entityID
的公共属性以及middleName
的唯一属性?此外,如果您有更好或更有效的设计方法的想法,我们将不胜感激 这看起来正是你应该做的。有一个基类读入公共属性,还有一个子类读入它们的特定属性
例如,我当前的代码是否最终创建了NNEntity和NNSubEntity2的and实例<代码>nEntity*newEntity=[[NNSubEntity2 alloc]init]代码>
没有。运行此命令时,实例化NNSubEntity2
,并将结果存储在由其超类键入的变量中,该变量是完全有效的。这允许您调用在超类上定义的任何方法,但实际实例仍然是子类的实例
newEntity是否正确设置了entityID的公共属性和middleName的唯一属性
当然会的。它继承超类中的实例变量、属性和方法
请放心,据我所知,这看起来不错,而且是我以前使用过的模式。我就是这样做的
// 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:forundinedkey:
的强大实现,我认为它是安全的,而且非常灵活
秘密就在苹果漂亮的技术中。本质上,setValuesForKeysWithDictionary:
迭代您给它的dict的键,并在其接收器中为每个hinvokessetValue:forKey:
。它看起来是这样的(尽管我确信苹果在幕后对它进行了优化):
我也喜欢这种方法,因为转换为更简单;当您告诉CoreData“渲染”您的模型时,它只会覆盖您的存根模型类,保持KVC类别不变。更重要的是,如果您的setValue:forundeindekey:
实现顺利,您可以在不破坏应用程序的情况下对后端进行模型更改(这有点不允许,但与出厂解决方案没有太大区别)
当然,我没有提到您需要有选择地选择实例化哪个类。但这是一个更大的设计问题,甚至可能受到API和后端设计的影响。所以我推迟了
此外,正如您在下面的评论中所指出的,属性名称必须匹配。这对某些开发人员来说是一个阻碍,尤其是当您无法同时控制后端和客户端时
试试看。欢迎反馈。谢谢!一个小的跟进。当我从API中获取字典列表(数组)时,每个字典都有一个
类型
键。我正在考虑在nEntity
类中创建一个(工厂)方法,比如+(nEntity*)initWithType:(NSString*)typeStringFromAPI
。这将确定它应该创建并返回的子类的类型。在nEntity
中使用这样的工厂方法有意义吗?或者我应该创建一个不同的工厂类来实现这一点吗?再次感谢您的回答。在NSEntity
超类中,您可以将类型映射到类名,并与NSClassFromString()
组合以获取要实例化的正确类。明白了。谢谢你的指导。我通常不会看到有人问如何做出好的设计+1至::)这很有趣,谢谢你的回复。我假设我的模型对象上的属性必须与我从API获得的键的名称相匹配。如果没有,或者有一个我不期望的新的,则必须通过setValue:forUndefinedKey:
方法来处理。我相信我会将这种方法与上面的方法结合起来,来确定子类类型并尝试一下。是的,它是正确的——它们必须逐字匹配。这是一个缺点。模型类中的额外或拼写错误的属性不会成为问题,API中的额外或拼写错误的属性将由setValue:forUndefinedKey:
处理。只要他们匹配,你就会成功。非常感谢这种方法。在过去的一年里一直在使用它,没有任何问题。在我控制API和iOS客户端的情况下,它非常非常有效。
-(void)setValuesForKeysWithDictionary:(NSDictionary *)dictionary {
NSArray *keys = [dictionary allKeys];
for (NSString* key in keys) {
[self setValue:[dictionary valueForKey:key] forKey:key];
}
}