2010-11-21 11 views
1

DBヘルパークラスには2つの異なるデータベースエンティティで基本的に同じ2つのメソッドがありますが、それらをリファクタリングしてコードの重複を避けたいと思います。この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)へのデータ。後者は私が一般化するのが特に難しいことです。

これら2つの方法をどのようにリファクタリングしますか?したほうがいい?

+0

[FMDB](http://github.com/ccgus/fmdb)を使用してください。 –

+0

しかし、私はこの特定のコードをどのようにリファクタリングするのか学ばないでしょう。 ;) – hpique

答えて

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

+0

Obj-Cは抽象クラスを持っていないと言う人はいますか?最高のセマンティック部門。もしあなたが本当にこのインスタンス化されたものがrootクラスのinitメソッドで例外をスローしたいのであれば、 –

+0

実際に編集すると、メソッドsigの共通性が削除されます。リファクタリングをしないでください。 –

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); 
} 

、差が1項目のためであるということであり、他方はコレクション用であることが表示されます。アイテムをコレクションに入れてからinsertOrUpdateCollection()を呼び出すことができれば、完了です。私は客観的なCを知らない。 JavaではCollections.singleton()を使用しています。

の指定されたオブジェクトのみを含む不変のセットを返します。

+0

初期の返品を指摘してくれてありがとう。しかし、この場合は、文を確定していません。 「コレクション」と「アイテム」に関しては、名前が偶然だったので、私はそれをより一般的にするために編集しました。 – hpique

2

まず、このために継承を使用しないでください。継承はインターフェイスを共有するためのものであり、実装を共有するものではありません。非常に似通った実装を持つ2つのメソッドがありますが、インタフェースは異なります。

次に、GoFによって宣言されている主な原則の1つを考えます。変更内容を特定してカプセル化します。この場合、これを行う最も簡単な方法は、いくつかの意味のある方法を抽出することです。それ以外の場合は、コードを読みやすくなります。あなたは(私は本当にあなたのコードが何をしているか分からないので、私は、擬似コードを使用しています)、このようなもののために撮影する必要があります。

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

あなたは、より多くのそのようなものを持っていたら、共通点のどちらかでしょう自分自身をよりはっきりと提示するか、またはメソッドが実際にはっきりとしたものでなければならないことを発見します。

関連する問題