3

我喜欢并使用 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
{
}

缺点:可选的构造函数参数意味着现在可以实例化此类,而无需为其提供所需的一切。

...那么,我还缺少其他选择吗?还是我只需要选择最不打扰我的那个?

4

1 回答 1

1

选项 3,但将对象作为可选参数听起来最好 imo:

public function __construct(IUserRepository $userRepository = new UserRepository()) {
    $this->userRepository = $userRepository;
}
于 2012-12-19T21:48:00.433 回答