在PHP中重构这两个非常相似的类的OO方法是什么?

时间:2010-10-04 21:27:25

标签: php oop refactoring

我有一个如下课程:

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_id,{{1 } dream_id中的{}将SQL

我知道有更好的方法可以做到这一点,我将在未来实施类似的类,这些类有很小的差异。

重构代码以避免重复并提高可维护性的最佳面向对象方法是什么?

2 个答案:

答案 0 :(得分: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直接实例化它并按如下方式调用它: / p>

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

另一种方法也可能是在ImagesStore中实现静态工厂方法。

答案 1 :(得分:2)

使用Richard Cook创建的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');