我有一个如下课程:
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
。
我知道有更好的方法可以做到这一点,我将在未来实施类似的类,这些类有很小的差异。
重构代码以避免重复并提高可维护性的最佳面向对象方法是什么?
答案 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.
}
并创建DreamsImagesStore
和InterestsImagesStore
专精:
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');