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

同様のユース ケースでの Factory または Builder Desing パターンの使用に関するさまざまな記事を読みましたが、このかなり単純なケースでそれが必要かどうかに興味があります。たとえば、現在のコードは と の両方のインスタンスを作成することになりますNNEntityNNSubEntity2? 次のようなものを呼び出す場合:

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 の美しいKey-Value Codingテクノロジーにあります。基本的に、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 に答える