2010-11-21 78 views
1

我有兩個DB Helper類中的方法,它們對兩個不同的數據庫實體做基本相同的事情,並且我想重構它們以避免重複代碼。如何重構此Objective-C代碼

第一實體:

- (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語句(RMSQLEntityAExistsRMSQLEntityBExists等)的常數和方法用於結合將數據發送到SQLite語句(bindEntityAbindEntityB)。後者是我發現特別具有挑戰性的概括。

我該如何重構這兩種方法?我是不是該?

+0

使用[FMDB](http://github.com/ccgus/fmdb)。 – 2010-11-21 23:46:26

+0

但是,我不會學習如何重構這個特定的代碼。 ;) – hpique 2010-11-22 20:15:52

回答

0

在根對象中將這兩個實體都與該方法的公用對象相關聯。

差分可以使用在子類的init方法設置實例變量和一個突變的方法

像這樣的調用出來進行修改......

@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); 
    } 
+0

這不會創建一個無法實例化的額外類嗎?由於Objective-C沒有抽象類,我覺得這可能是誤導性的。另外,我編輯了這個問題,使兩個方法都在db助手類中更清晰。 – hpique 2010-11-21 19:46:10

+0

誰說Obj-C沒有抽象類?它最多是一個語義分工。如果你真的不想這個實例化在根類init方法中拋出一個異常。 – 2010-11-21 20:13:10

+0

實際上,您的編輯刪除了方法sig中的通用性。不要打擾重構。 – 2010-11-21 20:16:03

0

我會改變的第一件事就是增加早期回報;縮進較少的代碼是那麼嚇人:

- (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

感謝您指出提前退貨。但是,在這種情況下,您並未完成這些陳述。關於「收藏品」和「物品」,名稱是偶然的,所以我編輯了這個問題以使其更通用。 – hpique 2010-11-22 20:25:59

2

首先,你不應該爲此使用繼承。繼承是用於共享接口,而不是用於共享實現。你有兩個非常相似的實現方法,但接口不同。其次,考慮GoF宣佈的主要原則之一:確定哪些變化並將其封裝。在這種情況下最簡單的方法是提取一些有意義的方法。如果沒有其他,這會讓你的代碼更容易閱讀。您應該拍攝這樣的事情(我使用僞代碼,因爲我真的不知道你的代碼做什麼):

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

一旦你擁有的東西,看起來更像是那麼的共性要麼讓自己更清楚,否則你會發現這些方法實際上應該保持截然不同。