How can I use Yii components while keeping my serv

Yii框架组件与服务层集成
本文探讨了如何在保持业务逻辑独立于框架的前提下,将实现了特定接口的服务层类作为Yii框架的组件使用。作者面临的问题是服务层类的构造函数需要参数,而Yii组件的构造函数不能有任何参数。文中提出了几种解决方案并分析了各自的利弊。
How can I use Yii components while keeping my service layer abstracted?


I like and use the Yii framework, particularly its "components", which are lazily-instantiated and you can swap them in or out in your configuration file. Kind of like a dependency injection-lite.

I try to keep the business logic of my code completely independent of the Framework, in case I ever want to repurpose that code, or even change frameworks.

Let's say I have a class in my service layer called AccountService, which implements IAccountService and has a one-argument constructor.

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);
  }
}
Great. So far, it's totally framework-free. Now I'd like to expose this as a Yii component, so it can be lazily-instantiated and easily used by Yii controllers and other Yii components.

But Yii components (which implement IApplicationComponent) must have exactly zero constructor arguments, while my class requires one!

Any ideas?

Here's what I've got. I'm not really happy with any of them; they both look over-engineered and I'm detecting a distinct smell from them.

Option 1 - compose: I create a class called "AccountServiceComponent" which implements Yii's IApplicationComponent. It cannot extend my AccountService class, because of the constructor, but it could instantiate one as a private member and wrap all of its methods, like so:

class AccountServiceComponent implements IApplicationComponent, IAccountservice
{
  private $_accountService;

  public __construct() {
    $this->_accountService = new AccountService(new UserRepository());
  }

  public getUserById($id) {
    return $this->_accountService->getUserById($id);
  }
}
Cons: I'll have to wrap every method like that, which is tedious and could lead to "baklava code." Especially considering that there'll be multiple service classes, each with multiple methods.

Option 2 - mixin: (Or behavior or trait or whatever it's called these days.)

Yii (having been written prior to PHP 5.4) offers "behaviors" in the form of a class which implements IBehavior. I could create a behavior class which extends my service, and attach it to a component:

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);
}
Cons: My component no longer officially implements IAccountService. Also seems to be getting excessive with the layering.

Option 3 - optional constructor parameters:

I could just make the constructor parameter to my service class optional, and then extend it into a component:

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
{
}
Cons: The optional constructor parameter means this class coudld now be instantiated without supplying it with everything it needs.

...so, any other options I'm missing? Or am I just going to have to choose the one that disturbs me the least?


转载于:https://my.oschina.net/yonghan/blog/534092

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值