2010-10-04 58 views
5

我有這樣一類以下內容:在PHP中重構這兩個非常相似的類的OO方式是什麼?

class DreamsImagesStore 
{ 
    public $table = 'dreams_images'; 

    public function insertNewDreamImage($dream_id, $pid) 
    { 
    try { 
     $values = array($dream_id, $pid); 
     $sth = $this->dbh->prepare("INSERT INTO {$this->table} 
           (dream_id, pid) 
           VALUES (?, ?)"); 
     if($sth->execute($values)) { 
     return true; 
     } 
    } catch(PDOException $e) { 
     $this->errorLogger($e); 
    } 
    } 
... 
} 

我將要實施一項名爲InterestsImagesStore新的類,其中這些類之間的唯一區別將是$table值,$dream_id$interest_iddream_idSQL將是interest_id

我知道有一個更好的方法來做到這一點,而且我將在未來實施類似的課程,這些課程的差異很小。

什麼是最好的面向對象的方式來重構我的代碼,以避免重複和增加可維護性?

+3

+1用於識別何時需要幫助*在創建需要由其他人重構的雜亂混亂之前 – Zak 2010-10-04 21:42:27

+0

@Zak謝謝。我嘗試編碼,就像跟在我後面的人是一個殺人狂。當我無法理解大部分正在說的模式書時,我想到一個真實有意義的例子可以幫助我將自己的思想包圍起來。 – 2010-10-04 21:52:42

回答

11

創建ImagesStore基類:

class ImagesStore 
{ 
    // See comments about accessors below. 
    private $table; 
    private $id_column; 

    public function insertImage($id, $pid) { 
    try { 
     $values = array($id, $pid); 
     $table = $this->getTable(); 
     $id_column = $this->getIdColumn(); 
     $sth = $this->dbh->prepare("INSERT INTO {$table} ($id_column, pid) VALUES (?, ?)"); 
     if ($sth->execute($values)) { 
     return true; 
     } 
    } 
    catch (PDOException $e) { 
     $this->errorLogger($e); 
    } 
    } 

    protected function __construct($table, $id_column) { 
    $this->table = $table; 
    $this->id_column = $id_column; 
    } 

    // These accessors are only required if derived classes need access 
    // to $table and $id_column. Declaring the fields "private" and providing 
    // "protected" getters like this prevents the derived classes from 
    // modifying these values which might be a desirable property of these 
    // fields. 
    protected function getTable() {return $this->table;} 
    protected function getIdColumn() {return $this->id_column;} 

    // More implementation here... 
    // Initialize $dbh to something etc. 
    // Provide "errorLogger" method etc. 
} 

,創造DreamsImagesStoreInterestsImagesStore專業:

class DreamsImagesStore extends ImagesStore { 
    public function __construct() { 
    parent::__construct('dreams_images', 'dream_id'); 
    } 
} 

class InterestsImagesStore extends ImagesStore { 
    public function __construct() { 
    parent::__construct('interests_images', 'interest_id'); 
    } 
} 

最初的方法insertNewDreamImage可以被重命名爲insertImage因爲它實際上是比原來更普遍名字暗示。

請注意,ImagesStore也可以聲明爲abstract如果您想阻止它的直接實例化。

可以採用另一種方法是不從ImagesStore都懶得派生類,只是通過使__construct方法public並調用它,如下所示實例化它直接:

$dreamsImagesStore = new ImagesStore("dreams_images", "dream_id"); 

另一種方法也可能是在ImagesStore中實施靜態工廠方法。

+0

感謝您的支持。在'insertImage()'中,你是不是指'$ this-> table'而不是'$ table'?如果不是,爲什麼? – 2010-10-04 21:43:36

+3

+1,但是甚至有必要使用硬編碼值進行子類化?如何創建一個將商店類型作爲參數的工廠函數,並返回圖像商店的適當實例? – Zak 2010-10-04 21:45:34

+2

@Josh Smith:兩種方法都有效。這個實現說明了通過getter方法訪問這些字段,但是這些字段同樣可以直接作爲基類方法中的$ this-> table和$ this-> id_column來訪問。派生類中的方法必須使用'getTable'和'getIdColumn'來代替,因爲我聲明瞭「private」字段。對於基類方法中的代碼,要麼是正確的,要歸功於味道。 – 2010-10-04 21:46:21

2

使用由理查德·庫克創建ImagesStore類,這也可能發生:

function FactoryLoadImageStore($imageStoreType) 
{ 
    switch($imageStoreType) 
    { 
     case "Interests": 
      return new ImageStore('interests_images', 'interest_id'); 
     case "Dreams": 
      return new ImageStore('dreams_images', 'dreams_id'); 
     default: 
      throw new Exception("ImageStore type $imageStoreType not found") 
; } 

} 

,或者你甚至可以更大膽的嘗試和做類似

function FactoryLoadImageStore($imageStoreType) 
{ 
    $tableName = $imageStoreType . 's_images'; 
    $idColumnName = $imageStoreType . 's_id'; 
    $tableExists = false; 
    $sql= "Show tables like '$tableName' "; 
    foreach ($this->dbh->query($sql) as $row) 
    { 
     if ($row['tableName'] == $tableName) 
     { 
      $tableExists = true; 
      break; 
     } 
    } 
    if(!$tableExists) 
    { 
     throw new Exception ("No matching table exists for the requested image store $imageStoreType"); 
    } 

    return new ImageStore($tableName, $idColumnName); 
} 

電話如下

$dreamImageStore = ImageStore::FactoryLoadImageStore('dream'); 
+0

不能記住表名是否在行中作爲tableName返回..應該檢查... – Zak 2010-10-04 22:12:24

相關問題