2010-11-21 5 views
1

두 개의 다른 데이터베이스 엔티티에 대해 기본적으로 동일한 작업을 수행하는 두 가지 메소드가 DB 도우미 클래스에 있으며 코드 복제를 피하기 위해 리팩토링하고 싶습니다.이 Objective-C 코드를 리팩토링하는 방법

제 1 엔티티 :

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

차이는 (등 RMSQLEntityAExists, RMSQLEntityBExists) SQL 문에 사용되는 상수 및 방법 SQLite 문의 데이터 (bindEntityAbindEntityB). 후자는 내가 일반화하기가 특히 어려웠다.

어떻게이 두 가지 방법을 리팩터링합니까? 해야합니까?

+0

[FMDB] (http://github.com/ccgus/fmdb)를 사용하십시오. –

+0

하지만이 특정 코드를 리팩토링하는 방법을 배우지는 않습니다. ;) – hpique

답변

0

두 개체를 루트 개체의 해당 메서드를 사용하여 공통 개체에서 상속합니다.

차동는 ... 당신이 서브 클래스의 초기화 방법에 설정 인스턴스 변수와 돌연변이 방법과 같이

를 호출 아웃을 사용하여 수정할 수 있습니다

@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에 추상 클래스가 없다고합니까? 그것은 시맨틱 디비전이다. 만약 당신이 정말로 원하지 않는다면,이 인스턴스화는 루트 클래스 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); 
} 

, 차이가 하나의 항목이다이고, 다른 하나는 컬렉션을위한 것으로 보인다. 항목을 콜렉션에 넣은 다음 insertOrUpdateCollection()을 호출하면 작업이 완료된 것입니다. 나는 객관적인 C를 모른다. Java에서는 Collections.singleton()을 사용합니다. 설명서의 내용대로 :

지정된 객체 만 포함하는 불변 세트를 반환합니다.

+0

조기 반품을 지적 해 주셔서 감사합니다. 그러나이 경우 귀하는 진술을 확정하지 않습니다. "콜렉션"과 "아이템"에 대해서는 이름이 우발적 인 것이므로 좀 더 일반적인 이름으로 편집했습니다. – hpique

2

우선, 상속을 사용해서는 안됩니다. 상속은 인터페이스 공유를위한 것이지 공유 구현을위한 것이 아닙니다. 매우 유사한 구현이지만 인터페이스가 다른 두 가지 방법이 있습니다.

둘째, GoF에서 선언 한 기본 원칙 중 하나가 무엇인지 확인하고 변경 내용을 캡슐화합니다. 이 경우 가장 쉬운 방법은 몇 가지 의미있는 방법을 추출하는 것입니다. 다른 것이 있으면 코드를 읽기 쉽게 만듭니다. 당신은 (내가 정말 코드가 무엇을하고 있는지 알 수 없기 때문에 내가 의사 코드를 사용하고 있습니다)이 같은 뭔가를 촬영해야합니다

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

당신이 후 더 그렇게 보이는 뭔가를 일단 공통점 중 하나 것 자신을 더 분명히 제시하거나, 실제로 그 방법이 분명하게 남아 있어야한다는 것을 알게 될 것입니다.

관련 문제