我有各种类,其方法具有相同的代码。维护观点是一种非常糟糕的做法。
这是这个类的一个例子:
班级帐户控制器:
<?php
namespace controller\admin;
class accountController extends \controller\baseController
{
private $table = 'account';
public function itemslist()
{
list($res, $totalcount) = $this->getResultAndCount();
return $this->twig->render('/admin/accounts.html.twig');
}
.
... other methods
.
private function getResultAndCount()
{
$sql = 'SELECT * FROM ' . $this->table;
$count = $this->pdo->rowCount();
$rows = $this->pdo->resultset();
return array($rows, $count);
}
}
类userController:
<?php
namespace controller\admin;
class userController extends \controller\baseController
{
private $table = 'user';
public function itemslist()
{
list($res, $totalcount) = $this->getResultAndCount();
return $this->twig->render('/admin/users.html.twig');
}
.
... other methods
.
private function getResultAndCount()
{
$sql = 'SELECT * FROM ' . $this->table;
$count = $this->pdo->rowCount();
$rows = $this->pdo->resultset();
return array($rows, $count);
}
}
如图所示,具有相同代码的方法getResultAndCount是重复的。不是OOP的专家我一直在寻找在某处只有一个代码的方法,并在itemslistAction()方法中引用它。
我已经看到了这样做的方法,就像拥有这个方法的另一个类并在父类中调用它,接口,方法一样......但我很困惑,我想知道这将是实现它的最好方法以及如何。
答案 0 :(得分:0)
你的两个课程都扩展了\controller\baseController
课程。您可以将复制函数放在\controller\baseController
类中,但如果您有其他扩展\controller\baseController
的类,并且如果您将仅在您声明的类中使用此函数,则可以创建一个新类,扩展<?php
namespace controller\admin;
class bridgeClass extends \controller\baseController
{
//...
protected function getResultAndCount()
{
$sql = 'SELECT * FROM ' . $this->table;
$count = $this->pdo->rowCount();
$rows = $this->pdo->resultset();
return array($rows, $count);
}
}
?>
并在此类中实现重复功能。
bridgeClass
我们在上面声明的private
中实现了该功能。另请注意,我们将函数的可见性从protected
更改为bridgeClass
,以便子类可以毫无问题地访问函数。然后,您可以使两个类扩展bridgeClass
。因此,在这种情况下,现在您的两个班级都有\controller\baseController
和\n
作为他们的父母。
答案 1 :(得分:0)
<?php
namespace controller\admin;
abstract class baseController
{
private $table;
public function itemslist()
{
list($res, $totalcount) = $this->getResultAndCount();
return $this->twig->render('/admin/accounts.html.twig');
}
private function getResultAndCount()
{
$sql = 'SELECT * FROM ' . $this->table;
$count = $this->pdo->rowCount();
$rows = $this->pdo->resultset();
return array($rows, $count);
}
}
班级帐户控制器:
<?php
namespace controller\admin;
class accountController extends \controller\baseController
{
private $table = 'account';
// more method ....
}
类userController:
<?php
namespace controller\admin;
class userController extends \controller\baseController
{
private $table = 'user';
// more method ....
}
答案 2 :(得分:0)
只是划伤:
interface IValue{
public function value();
}
class DBQuery implements IValue{
private $pdo;
private $sql;
public function __construct(...){
....
}
public function value(){
// execute $this->sql
}
}
class LazyTemplate{
private $twig;
private $template;
private $data;
public function __construct(..., IValue $data){
....
}
public function render(){
return $this->twig->render(
$this->template,
$this->data->value()
);
}
}
namespace controller\admin;
class accountController extends \controller\baseController
{
private $items;
public function __construct(...){
$this->items = new LazyTemplate(
$this->twig,
'/admin/accounts.html.twig',
new DBQuery($this->pdo, 'SELECT * FROM account')
);
}
public function itemslist()
{
return $this->items->render();
}
}
class userController extends \controller\baseController
{
private $items;
public function __construct(...){
$this->items = new LazyTemplate(
$this->twig,
'/admin/users.html.twig',
new DBQuery($this->pdo, 'SELECT * FROM user')
);
}
public function itemslist()
{
return $this->items->render();
}
}
P上。秒。我不知道Twig API,所以可能有更好的方法。
许多人建议使用继承来删除重复的代码。实际上,继承允许您快速而简单地执行此操作,但请考虑此方法的缺点:
我们的课程越来越大,虽然领域模型不需要它。
我们可能很容易需要一些列表,但我们只提供了一个继承。进一步炸毁基类?
其他地方可能需要列表。将代码复制到那里并再次复制?
我们只是使测试复杂化。有必要添加一个易于测试的非常小的方面,但现在我们拥有整个层次结构的这一部分。
这是出于我们的意图。重复代码我们真的想说什么? - 我会这样说:“有必要 以某种方式 来获取数据, *以某种方式* 将它们传输到模板”。 “ 以某种方式 ”,我想说,是抽象的界限,那些应该在不同实体中突出显示的地方。
“ 以某种方式 将它们(数据)传输到模板” - 是某种实体,根据需要,获取数据,将其提供给模板并返回渲染的结果。我调用了这个实体LazyTemplate
,因为它执行“惰性计算”(即使没有缓存,因为它通常会发生)。
LazyTemplate
可以立即或通过闭包接收数据,但我选择了接口IValue
。接口是“严格类型”,我们可以轻松地通过PHP本身提供参数检查(5.0+)。此外,我们在紧急情况发生之前不需要这些数据。如果我们的列表被隐藏,那么执行查询到DB是没有意义的。 IValue
只是LazyTemplate
与其环境之间的契约。
“ 以某种方式 获取数据” - 这是另一个实体。理想情况下,此实体不应指定此数据的来源,但为简单起见,我决定立即描述类DBQuery
。此外,我们已经有IValue
,它执行相同的功能。
当然,我们必须引入几个额外的抽象(非常小的抽象,值得注意),但现在我们可以重用它们,扩展它们(例如,通过创建类CachedValue
,{{1只测试一个特定的功能。
控制器仍然有类似的代码行,但不要盲目地尝试根除重复。用户列表和帐户列表是两个 不同的 列表,它们将来可能会变得完全不兼容。
P上。秒。我为任何错误道歉。