Как провести рефакторинг этого кода Objective-C - PullRequest
1 голос
/ 21 ноября 2010

У меня есть два метода в классе помощника БД, которые в основном делают одно и то же для двух разных объектов базы данных, и я хотел бы реорганизовать их, чтобы избежать дублирования кода.

Первая сущность:

- (void) insertOrUpdateEntityA:(NSDictionary*)data {
    sqlite3_stmt *exists_stmt;
    if(sqlite3_prepare_v2(database, RMSQLEntityAExists, -1, &exists_stmt, NULL) == SQLITE_OK) {
        [RMStoreDB bindPrimaryKey:exists_stmt data:data from:1];
        if (sqlite3_step(exists_stmt) == SQLITE_ROW) {
            int count = sqlite3_column_int(exists_stmt, 1);
            sqlite3_stmt *update_stmt;
            if (count) { // Update
                if (sqlite3_prepare_v2(database, RMSQLEntityAUpdate, -1, &update_stmt, NULL) == SQLITE_OK) {
                    int index = [RMStoreDB bindEntityA:update_stmt data:data from:1];
                    [RMStoreDB bindPrimaryKey:update_stmt data:data from:index];
                }
            } else { // Insert
                if (sqlite3_prepare_v2(database, RMSQLEntityAInsert, -1, &update_stmt, NULL) == SQLITE_OK) {
                    int index = [RMStoreDB bindPrimaryKey:update_stmt data:data from:1];
                    [RMStoreDB bindEntityA:update_stmt data:data from:index];
                }           
            }
            sqlite3_step(update_stmt);
            sqlite3_finalize(update_stmt);
        }           
    }
    sqlite3_finalize(exists_stmt);
}

Вторая сущность:

 - (void) insertOrUpdateEntityB:(NSDictionary*)data {
    sqlite3_stmt *exists_stmt;
    if(sqlite3_prepare_v2(database, RMSQLEntityBExists, -1, &exists_stmt, NULL) == SQLITE_OK) {
        [RMStoreDB bindPrimaryKey:exists_stmt data:data from:1];
        if (sqlite3_step(exists_stmt) == SQLITE_ROW) {
            int count = sqlite3_column_int(exists_stmt, 1);
            sqlite3_stmt *update_stmt;
            if (count) { // Update
                if (sqlite3_prepare_v2(database, RMSQLEntityBUpdate, -1, &update_stmt, NULL) == SQLITE_OK) {
                    int index = [RMStoreDB bindEntityB:update_stmt data:data from:1];
                    [RMStoreDB bindPrimaryKey:update_stmt data:data from:index];
                }
            } else { // Insert
                if (sqlite3_prepare_v2(database, RMSQLEntityBInsert, -1, &update_stmt, NULL) == SQLITE_OK) {
                    int index = [RMStoreDB bindPrimaryKey:update_stmt data:data from:1];
                    [RMStoreDB bindEntityB:update_stmt data:data from:index];
                }           
            }
            sqlite3_step(update_stmt);
            sqlite3_finalize(update_stmt);
        }           
    }
    sqlite3_finalize(exists_stmt);
}

Различия - это константы, используемые для операторов SQL (RMSQLEntityAExists, RMSQLEntityBExists и т. Д.), И метод, используемый для привязки данных к оператору SQLite (bindEntityA и bindEntityB). Последнее, что я считаю особенно сложным для обобщения.

Как мне провести рефакторинг этих двух методов? Должен ли я?

Ответы [ 3 ]

2 голосов
/ 22 ноября 2010

Прежде всего, вы не должны использовать наследование для этого.Наследование предназначено для совместного использования интерфейса, а не для совместного использования реализации.У вас есть два метода с очень похожими реализациями, но с разными интерфейсами.

Во-вторых, рассмотрим один из основных принципов, объявленных GoF: определить, какие изменения и инкапсулировать их.Самый простой способ сделать это в этом случае - извлечь некоторые значимые методы.Если ничего другого, это облегчит чтение вашего кода.Вы должны стрелять за что-то вроде этого (я использую псевдокод, так как я действительно не знаю, что делает ваш код):

- (void)insertOrDeleteItem:(NSDictionary *)item {
    if ([self databaseAppearsToBeWorking]]) {
        row = [self findRowForItem:item];
        if (row) {
            [self updateRow:row withItem:item];
        } else {
            [self insertItem:item];
        }
    }
}

Как только у вас есть что-то, что больше похоже на это, то общностьлибо представится более четко, либо вы обнаружите, что методы на самом деле должны оставаться различными.

0 голосов
/ 22 ноября 2010

Первое, что я бы изменил, это добавление ранних возвратов; код с меньшим отступом менее пугающий:

- (void) insertOrUpdateItem:(NSDictionary*)item {
    sqlite3_stmt *exists_stmt;
    if (sqlite3_prepare_v2(database, RMSQLItemExists, -1, &exists_stmt, NULL) != SQLITE_OK) 
        return;
    [RMStoreDB bindPrimaryKey:exists_stmt data:item from:1];
    if (sqlite3_step(exists_stmt) != SQLITE_ROW)
        return;
    int count = sqlite3_column_int(exists_stmt, 1);
    sqlite3_stmt *update_stmt;
    if (count) { // Update
        if (sqlite3_prepare_v2(database, RMSQLItemUpdate, -1, &update_stmt, NULL) == SQLITE_OK) {
            int index = [RMStoreDB bindItem:update_stmt data:item from:1];
            [RMStoreDB bindPrimaryKey:update_stmt data:item from:index];
        }
    } else { // Insert
        if (sqlite3_prepare_v2(database, RMSQLItemInsert, -1, &update_stmt, NULL) == SQLITE_OK) {
            int index = [RMStoreDB bindPrimaryKey:update_stmt data:item from:1];
            [RMStoreDB bindItem:update_stmt data:item from:index];
        }           
    }
    sqlite3_step(update_stmt);
    sqlite3_finalize(update_stmt);
    sqlite3_finalize(exists_stmt);
}

Кроме того, похоже, что разница в том, что один для предметов, а другой для коллекций. Если вы можете поместить элемент в коллекцию и затем вызвать insertOrUpdateCollection (), все готово. Я не знаю цель C; в Java мы будем использовать Collections.singleton (), который, как сказано в документации:

Возвращает неизменный набор, содержащий только указанный объект.

0 голосов
/ 21 ноября 2010

Субкласс обоих сущностей от общего объекта с этим методом в корневом объекте.

Дифференциал можно изменить, используя ivars, который вы установили в методах инициализации подкласса, и вызовом мутированного метода

Вот так ...

@interface RootEntity : MyObject {

    NSString *statementmech1;
    NSString *statementmech2;
    NSString *statementmech3;
}

@interface Entity1 : RootEntity {

}

@interface Entity2 : RootEntity {

}

и

@implementation RootEntity

-(void)variantMethod
{
  //varies in subclasses
}

    - (void) insertOrUpdateItem:(NSDictionary*)item {
        sqlite3_stmt *exists_stmt;
        if(sqlite3_prepare_v2(database, statementmech1 , -1, &exists_stmt, NULL) == SQLITE_OK) {
            [RMStoreDB bindPrimaryKey:exists_stmt data:item from:1];
            if (sqlite3_step(exists_stmt) == SQLITE_ROW) {
                int count = sqlite3_column_int(exists_stmt, 1);
                sqlite3_stmt *update_stmt;
                if (count) { // Update
                    if (sqlite3_prepare_v2(database, statementmech2, -1, &update_stmt, NULL) == SQLITE_OK) {
                        int index = [RMStoreDB bindItem:update_stmt data:item from:1];
                        [RMStoreDB bindPrimaryKey:update_stmt data:item from:index];
                    }
                } else { // Insert
                    if (sqlite3_prepare_v2(database, statementmech3, -1, &update_stmt, NULL) == SQLITE_OK) {
                        [self variantMethod];
                    }           
                }
                sqlite3_step(update_stmt);
                sqlite3_finalize(update_stmt);
            }           
        }
        sqlite3_finalize(exists_stmt);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...