基本上我有一个方法,我需要在构造函数完成时运行(该方法被称为persist(),它只是将构造函数中生成的密钥保存到会话中)。它似乎很简单,并且它有效 - 在__construct结束时,我调用$ this-> persist()。
问题是这个类多次被子类化。这会导致两个问题。
一,我必须记住在每个子类的__construct方法的末尾调用persist()。这不是一个很大的问题,但它并没有感觉到非常OOP,我觉得我可以在父类中处理这个问题,这样做会更好。
二,如果子类是子类(它是),并且链接的__construct方法(即调用了父:: __构造),则persist()方法将被多次触发,每次类被触发一次子类。所有施工完成后,只需要调用一次。在这种情况下,它并没有真正破坏任何东西,因为当第二次,第三次等调用持久化方法时,它只是覆盖之前持久化的内容。但这不是重点,因为我觉得必须有更好的方法,并且有些场景不允许多次调用该方法。
是一个构造对象的工厂方法,然后以唯一的方式使调用持久化吗?我可以沿着这条路走下去,但我只是想知道是否有办法在没有这条路的情况下做到这一点,以便在构建之后总是调用父方法。
以下是一些示例代码:
session_start();
is(!isset($_SESSION["Component"])) $_SESSION["Component"] = [];
abstract Class Component
{
private $id;
protected $key;
function __construct($id = NULL)
{
$this->id = $id;
$this->key = [];
$this->key["something"] = "SomeValue";
$this->persist(); // First call
}
protected function persist()
{
if($this->id !== NULL) $_SESSION["Component"][$this->id] = $this->key;
}
}
Class SomeComponent extends Component
{
function __construct($id = NULL)
{
parent::__construct($id);
$this->key["something-else"] = "SomeOtherValue";
$this->persist(); // Second call
}
}
Class SomeSpecialistComponent extends SomeComponent
{
function __construct($id = NULL, $key = [])
{
parent::__construct($id);
$this->key = array_merge($this->key, $key);
$this->persist(); // Third call
}
}
$my_component = new SomeSpecialistComponent(1, ["example" => true]);
答案 0 :(得分:2)
我发现只有一些类似的技巧(除了我想在之前而不是之后执行的东西)是使用带有抽象方法的父类作为新的构造函数:
abstract class RequireThings {
public function __construct() {
$this->constructAndPersist();
$this->persist();
}
abstract function constructAndPersist();
// You could also set this function in your children classes by the way.
public function persist() {
echo ' Then I persist!';
}
}
class UsingPersist extends RequireThings {
public function constructAndPersist() {
echo 'I do my things first.';
}
}
$class = new UsingPersist();
输出:
I do my things first. Then I persist!
如果我的问题得到解决,应该足以避免您遇到的问题。
这个解决方案的主要缺点是你必须使用一个新函数,它应该是这类类的新构造函数。这就是我将__constructPersist设置为抽象的原因,它强制了所需的行为。
答案 1 :(得分:1)
在$ this->之前创建另一个您调用的函数,并在子类而不是构造函数中覆盖它并将其覆盖
答案 2 :(得分:1)
我会支持工厂方法,主要是因为你是doing real work in the constructor。删除构造函数($this->persist
)中正在进行工作的调用并将其放在工厂中:
class ComponentFactory
{
const SOME_COMPONENT = 'component';
const SOME_SPECIALIST_COMPONENT = 'specialist_component';
public static function make($type, $id, $key = null)
{
switch($type) {
case self::SOME_COMPONENT:
$component = new SomeComponent($id);
break;
case self::SOME_SPECIALIST_COMPONENT:
$component = new SomeSpecialistComponent($id, $key);
break;
}
$component->persist();
return $component;
}
}
$component = ComponentFactory::make(ComponentFactory::SOME_COMPONENT, 42);
$specialist = ComponentFactory::make(
ComponentFactory::SOME_SPECIALIST_COMPONENT,
43,
[
'something' => 'SomeValue',
'something-else' => 'SomeOtherValue',
]
);
根据MiškoHevery(AngularJS的作者和谷歌的敏捷教练),这些是在构造函数中做太多工作的警告信号:
- 构造函数或字段声明中的新关键字
- 构造函数或字段声明中的静态方法调用
- 除了构造函数中的字段赋值之外的任何内容
- 构造函数完成后对象未完全初始化(观察 out for initialize methods)
- 构造函数中的控制流(条件或循环逻辑)
- CL在构造函数中执行复杂的对象图构造 而不是使用工厂或建筑商
- 添加或使用初始化块
醇>