基本上我有一个方法,我需要在构造函数完成时运行(该方法被称为persist(),它只是将构造函数中生成的密钥保存到会话中).它似乎很简单,并且它有效 – 在__construct结束时,我调用$this-> persist().
问题是这个类多次被子类化.这导致两个问题.
一,我必须记住在每个子类的__construct方法的末尾调用persist().这不是一个很大的问题,但它感觉不是非常OOP,我觉得我可以在父类中处理这个问题,并且这会更好.
第二,如果子类是子类(它是子类),并且链接的__construct方法(即调用了父:: __构造),则persist()方法将被多次触发,每次类被子类化一次.所有施工完成后,只需要调用一次.在这种情况下,它并没有真正破坏任何东西,因为当第二次,第三次等调用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]);
解决方法:
我支持工厂方法,主要是因为你是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的作者和谷歌的敏捷教练),这些是在构造函数中做太多工作的警告信号:
- new keyword in a constructor or at field declaration
- Static method calls in a constructor or at field declaration
- Anything more than field assignment in constructors
- Object not fully initialized after the constructor finishes (watch
out for initialize methods)- Control flow (conditional or looping logic) in a constructor
- CL does complex object graph construction inside a constructor
rather than using a factory or builder- Adding or using an initialization block