我喜欢并使用 Yii 框架,尤其是它的“组件”,它们是惰性实例化的,您可以在配置文件中将它们换入或换出。有点像依赖注入精简版。
我试图让我的代码的业务逻辑完全独立于框架,以防我想重新利用该代码,甚至改变框架。
假设我的服务层中有一个名为 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 - compose:我创建了一个名为“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);
}
}
缺点:我必须像这样包装每一个方法,这很乏味并且可能导致“果仁蜜饼代码”。特别是考虑到会有多个服务类,每个服务类都有多种方法。
选项 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
{
}
缺点:可选的构造函数参数意味着现在可以实例化此类,而无需为其提供所需的一切。
...那么,我还缺少其他选择吗?还是我只需要选择最不打扰我的那个?