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

Jos*_*ith 5 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);
    }
  }
...
}
Run Code Online (Sandbox Code Playgroud)

我将要实施一项名为InterestsImagesStore新的类,其中这些类之间的唯一区别将是价值$table,$dream_id$interest_iddream_idSQLinterest_id.

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

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

Ric*_*ook 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.
}
Run Code Online (Sandbox Code Playgroud)

并创建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');
  }
}
Run Code Online (Sandbox Code Playgroud)

原始方法insertNewDreamImage可以重命名为,insertImage因为它比原始名称更普遍.

请注意,如果要阻止对其进行直接实例化,ImagesStore也可以声明abstract.

可以采用的另一种方法是不打扰从中派生类ImagesStore,只需通过生成__construct方法public并按如下方式调用它来直接实例化它:

$dreamsImagesStore = new ImagesStore("dreams_images", "dream_id");
Run Code Online (Sandbox Code Playgroud)

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

  • +1,但是真的甚至需要使用硬编码值进行子类化吗?如何创建一个将商店类型作为参数的工厂函数,并返回图像存储的相应实例? (3认同)
  • @Josh Smith:两种方法都有效.这个实现说明了通过getter方法访问这些字段,但是这些字段同样可以直接从基类方法中的`$ this-> table`和`$ this-> id_column`访问.派生类中的方法必须使用`getTable`和`getIdColumn`,因为我已经声明了字段`private`.对于基类方法中的代码要么是正确的,要归结为品味. (2认同)