2

我的 Objective-c 类中有两种方法可以做类似但不同的事情。(它们都检索一组包含 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;

}

第二种方法如下所示:

+(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。然而,试图将这些方法组合成一个方法会引入一些复杂性,这会在某种程度上混淆每个单独的方法的作用。

任何人都可以就实现这两种方法所包含的功能的最优雅方式提供建议吗?坚持这两种方法?创造一种更复杂的方法?闯入不同的班级?

他们是这种场景的相关设计模式吗?谢谢。

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,所以让我写一些逻辑来代替。

在我看来,您的第二种方法可以通过以下方式简化:

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

您可能有兴趣阅读外观设计模式

于 2013-01-08T10:34:59.233 回答
0

使用设计模式访问者或命令。这使您可以将获取和迭代响应与要采取的操作分离。

你在这里有两件事:准备+循环+编组步骤和处理步骤。一部分相同(前者),一部分不同(后者)。所以你想排除后者,这样你就可以避免制作前者的多个副本。

您可以通过使处理步骤成为在子类中重载的虚拟方法,或者通过传入可以执行该步骤的“东西”来实现。这个“东西”通常是命令或访问者。

这一切都归结为您是要使用继承还是组合。就个人而言,我倾向于更喜欢作曲。

于 2013-01-08T11:09:34.707 回答