我喜欢并使用Yii框架,特别是它的“组件”,它们是懒惰实例化的,您可以在配置文件中交换它们。有点像依赖注入-lite。
我尝试保持代码的业务逻辑完全独立于Framework,以防我想重新调整代码,甚至更改框架。
假设我的服务层中有一个名为AccountService的类,它实现了IAccountService并且具有单参数构造函数。
interface IAccountService
{
function getUserById($id);
}
class AccountService implements IAccountService
{
private $_userRepository;
public function __construct(IUserRepository $userRepository) {
$this->_userRepository = $userRepository;
}
public function getUserById($id) {
return $this->_userRepository->getById($id);
}
}
大。到目前为止,它完全没有框架。现在我想把它作为Yii组件公开,所以它可以被懒惰地实例化,并且很容易被Yii控制器和其他Yii组件使用。
但是Yii组件(实现IApplicationComponent)必须具有完全零的构造函数参数,而我的类需要一个!
有什么想法吗?
这就是我所拥有的。我对他们中的任何一个都不满意;他们看起来都过度设计,我发现它们有明显的气味。
选项1 - 撰写:我创建了一个名为“AccountServiceComponent”的类,它实现了Yii的IApplicationComponent。它不能扩展我的AccountService类,因为构造函数,但它可以将一个实例化为私有成员并包装其所有方法,如下所示:
class AccountServiceComponent implements IApplicationComponent, IAccountservice
{
private $_accountService;
public __construct() {
$this->_accountService = new AccountService(new UserRepository());
}
public getUserById($id) {
return $this->_accountService->getUserById($id);
}
}
缺点:我必须将这样的每个方法包装起来,这很乏味,可能导致“baklava代码”。特别是考虑到会有多个服务类,每个类都有多种方法。
选项2 - mixin :(或行为或特质或者这些天所谓的任何东西。)
Yii(在PHP 5.4之前编写)以实现IBehavior的类的形式提供“行为”。我可以创建一个扩展我的服务的行为类,并将它附加到一个组件:
class AccountServicesBehavior extends AccountService implements IBehavior
{
// Implement the few required methods here
}
class AccountServiceComponent implements IApplicationComponent
{
public function __construct() {
$accountService = new AccountService(new UserRepository());
$this->attachBehavior($accountService);
}
缺点:我的组件不再正式实现IAccountService。分层也似乎过度了。
选项3 - 可选构造函数参数:
我可以将构造函数参数设置为我的服务类可选,然后将其扩展到一个组件中:
class AccountService implements IAccountService
{
public $userRepository;
public function __construct(IUserRepository $userRepository = null) {
$this->userRepository = $userRepository;
}
public function getUserById($id) {
return $this->_userRepository->getById($id);
}
}
class AccountServiceComponent extends AccountService implements IApplicationComponent
{
}
缺点:可选的构造函数参数意味着现在可以实例化此类coudld,而无需为其提供所需的一切。
...那么,我还缺少其他任何选择吗?或者我只能选择那个让我最不安的人?
答案 0 :(得分:1)
选项3但是将对象作为可选参数听起来最好是imo:
public function __construct(IUserRepository $userRepository = new UserRepository()) {
$this->userRepository = $userRepository;
}