2

私のobjective-cクラスには、似ているが異なることを行う2つのメソッドがあります。(どちらも、JSONを含むコアデータレコードのセットを取得し、JSONドキュメントを解凍して調べ、JSONの構造に応じていくつかの処理を実行します)。

最初のメソッドは次のようになります。

+(NSDictionary*)getListOfResponsesWithForm:(NSString*)formId
{
    NSError* requestError = nil;

    // NSIndexSets don't allow easy targetted access into the set, so use arrays instead.
    NSMutableArray* indexSetOfAllEntries = [[NSMutableArray alloc] init];
    NSMutableArray* indexSetOfEntriesForLoggedOnUser = [[NSMutableArray alloc] init];

    NSString* activeUserEmail = getActiveUser().email;


    NSFetchRequest* fetchRequest = [ [NSFetchRequest alloc] init];

    NSEntityDescription* entityDesc = [NSEntityDescription entityForName:@"Response" inManagedObjectContext:getApp().managedObjectContext];

    [fetchRequest setEntity:entityDesc];

    // Sort by lastmodifieddatelocal
    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"lastmodifieddatelocal" ascending:NO];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];

    NSArray* instances = [getApp().managedObjectContext executeFetchRequest:fetchRequest error:&requestError];

    NSMutableArray* responses = [[NSMutableArray alloc] init];

    for (Response* response in instances) {


        NSData *jsonData = [response.json dataUsingEncoding:NSUTF8StringEncoding];
        NSDictionary* dictionary = [HPSJSON getDictionaryFromDataWithoutSuccessTest:jsonData];

        NSString* userEmailFromResponse = [HPSJSON getStringForKey: @"_useremail" inDictionary:dictionary];

        NSString* formIdFromResponse =  [HPSJSON getNestedIdForKey: @"_formid" inDictionary: dictionary];

        if ([formId caseInsensitiveCompare:formIdFromResponse]==NSOrderedSame)
        {
            [responses addObject: response];

            [indexSetOfAllEntries addObject:[NSNumber numberWithInt:responses.count-1]];

            if ([activeUserEmail caseInsensitiveCompare:userEmailFromResponse]==NSOrderedSame)
            {
                [indexSetOfEntriesForLoggedOnUser addObject:[NSNumber numberWithInt:responses.count-1]];
            }

        }

    }

    NSMutableDictionary* results = [[NSMutableDictionary alloc] init];
    [results setObject:responses forKey:@"responses"];
    [results setObject:indexSetOfAllEntries forKey:@"allindexes"];
    [results setObject:indexSetOfEntriesForLoggedOnUser forKey:@"indexesforactiveuser"];

    return results;

}

2番目の方法は次のようになります。

+(NSInteger)getCountOfResponsesWithForm:(NSString*)formId
{
    NSError* requestError = nil;

    NSString* activeUserEmail = getActiveUser().email;

    NSFetchRequest* fetchRequest = [ [NSFetchRequest alloc] init];

    NSEntityDescription* entityDesc = [NSEntityDescription entityForName:@"Response" inManagedObjectContext:getApp().managedObjectContext];

    [fetchRequest setEntity:entityDesc];

    NSArray* instances = [getApp().managedObjectContext executeFetchRequest:fetchRequest error:&requestError];

    NSInteger countOfResponses=0;

    for (Response* response in instances) {

        NSData *jsonData = [response.json dataUsingEncoding:NSUTF8StringEncoding];
        NSDictionary* dictionary = [HPSJSON getDictionaryFromDataWithoutSuccessTest:jsonData];

        NSString* userEmailFromResponse = [HPSJSON getStringForKey: @"_useremail" inDictionary:dictionary];

        NSString* formIdFromResponse =  [HPSJSON getNestedIdForKey: @"_formid" inDictionary: dictionary];

        if ([formId caseInsensitiveCompare:formIdFromResponse]==NSOrderedSame)
        {
            if ([activeUserEmail caseInsensitiveCompare:userEmailFromResponse]==NSOrderedSame)
            {
                countOfResponses++;
            }

        }

    }

    return countOfResponses;

}

ここには重複コードがかなりあり、ある程度DRYを悪用している気がします。ただし、メソッドを1つのメソッドに結合しようとすると、個々のメソッドの機能が多少わかりにくくなる複雑な問題が発生します。

両方の方法に含まれる機能を実装するための最もエレガントな方法について誰かがアドバイスを提供できますか?2つの方法を使い続けますか?条件を散りばめたもう1つの複雑なメソッドを作成しますか?別のクラスに突入しますか?

それらはこのシナリオに関連するデザインパターンですか?ありがとう。

4

4 に答える 4

1

私は提案します:

  1. 共通のブロックを識別します(例:NSFetchRequest * fetchRequest ...、NSEntityDescription * entityDesc);

  2. 共通ブロックごとに、適切な引数を取得し、それらに必要なことを実行するメソッドを定義します。

  3. DRYを改善するために、このようなメソッドを呼び出します。例:

    <getInstances>
    <for each instance>
       <extract data from instance>
       <do your processing on data>
    

この場合、デザインパターンではなく、リファクタリングの観点から考えます。もちろん、これらすべてを独自のクラスにカプセル化することもできますが、現在コードが含まれているクラスが果たしている役割がわからないため、これ以上詳しくは言えません。

ところで、私はより高いレベルの抽象化でデザインパターンを使用する傾向があります(そのため、多くはアーキテクチャレベルでほとんど役立ちますが、デザインパターンと呼ばれます)。この場合、いくつかのリファクタリングレシピ(グーグルを見つけるかもしれないので)がより適していると思います。

于 2013-01-08T10:30:23.520 に答える
1

テンプレートデザインパターンを検討します。

基本的に、基本クラス内のテンプレートメソッドに基本的な動作をカプセル化し、基本クラスで定義された抽象メソッドを実装(またはオーバーライド)する基になる子クラス内に具体的な動作を実装します。

SOに関する興味深いリソース:Objective-C-テンプレートメソッドパターン?

于 2013-01-08T16:30:23.847 に答える
0

私はXcodeが苦手なので、代わりにロジックを書いてみましょう。

2番目の方法は次のように簡略化できるようです。

int getCountOfResponsesWithForm(String a)
{
    Dictionary dic  = getListOfResponsesWithForm(a);
    return dic.length();
}

あなたはファサードデザインパターンを読むことに興味があるかもしれません。

于 2013-01-08T10:34:59.233 に答える
0

デザインパターンVisitorまたはCommandを使用します。これにより、応答のフェッチと反復を、実行するアクションから切り離すことができます。

ここにあるのは、準備+ループ+マーシャリングステップと処理ステップの2つです。一部は同じ(前者)で、一部は異なります(後者)。したがって、後者を除外して、前者のコピーを複数作成することを回避できます。

これを行うには、処理ステップをサブクラスでオーバーロードされるダミーメソッドにするか、ステップを実行できる「何か」を渡します。この「何か」は通常、コマンドまたは訪問者のいずれかになります。

結局のところ、継承とコンポジションのどちらを使用するかということです。個人的には作曲を好む傾向があります。

于 2013-01-08T11:09:34.707 に答える