1

我担心这是一个相当简单的问题,但经过大量谷歌搜索后,我认为我已经超出了我的预期结果。我相信我的问题与设计模式有关,但可惜我可能是错的。

我的应用程序调用 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

我已经阅读了关于在类似用例中使用工厂或构建器设计模式的各种文章,但我很好奇在这个相当简单的情况下是否有必要这样做。例如,我当前的代码是否最终创建了这两个和实例,NNEntity如果NNSubEntity2我要调用这样的东西:

NNEntity *newEntity = [[NNSubEntity2 alloc] init];
//assume dict exists already and is properly keyed
[newEntity readFromDict:dict];

我假设不是,但是会newEntity同时具有正确设置的共同属性和entityID唯一属性middleName吗?此外,如果您对更好或更有效的设计方法有想法,我们将不胜感激。

4

2 回答 2

2

这看起来就像你应该做的那样。您有一个读取公共属性的基类,以及读取其特定属性的子类。

例如,我当前的代码是否最终创建了 NNEntity 和 NNSubEntity2 的实例?NNEntity *newEntity = [[NNSubEntity2 alloc] init];

没有。当你运行它时,你NNSubEntity2将结果实例化并存储在一个由它的超类键入的变量中,这是完全有效的。这允许您调用在超类上定义的任何方法,但实际实例仍然是子类的。

newEntity 是否正确设置了 entityID 的公共属性和 middleName 的唯一属性?

它肯定会的。它继承了超类中的实例变量、属性和方法。


请放心,据我所知,这看起来不错,并且是我以前使用过的模式。

于 2013-05-23T22:58:39.383 回答
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 漂亮的键值编码技术中。本质上,setValuesForKeysWithDictionary:迭代你给它的字典的键,并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 和后端设计的影响。所以我推迟。

此外,正如您在下面的评论中指出的那样,属性名称必须匹配。这对某些开发人员来说是一个阻碍,尤其是如果您无法同时控制后端和客户端。

试试看。欢迎反馈。

于 2013-05-23T23:34:25.517 回答