如何在保持服务层抽象的同时使用Yii组件?

时间:2012-12-19 20:16:55

标签: php yii service-layer

我喜欢并使用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,而无需为其提供所需的一切。

...那么,我还缺少其他任何选择吗?或者我只能选择那个让我最不安的人?

1 个答案:

答案 0 :(得分:1)

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

public function __construct(IUserRepository $userRepository = new UserRepository()) {
    $this->userRepository = $userRepository;
}