Laravel:服务/存储库模式和复制代码

时间:2016-06-09 13:12:24

标签: php laravel laravel-5 architecture repository-pattern

在我的项目中,我决定使用服务模式(可能使用存储库模式)来处理应用程序中的业务逻辑。我有一个代表客户的Client模型和一个负责客户特定业务逻辑的相应ClientService

class ClientService extends Service implements ClientServiceContract
{
    public function create(array $attributes)
    {
        // Create a new client...
    }

    public function doSomethingElse(Client $client)
    {
        // Do something else
    }
}

比如说我有另一项服务UserService,它类似于上面的ClientService,因为它有方法可以为User模型创建和做其他事情。

现在,在我的网站上,想象一下我有一个表格,有人可以填写,以注册他们成为客户的兴趣。在我的后端系统中,我想创建一个按钮来获取客户的兴趣记录ClientInterest并创建一个Client,一个User,将两者关联起来,最后发送一封电子邮件给带有详细信息的新用户。

在使用服务模式时,最好采用这种逻辑吗?

我考虑过:

  1. 创建一个服务和方法ClientInterestService::createClientAndUser(...),它将使用ClientServiceUserService类创建ClientUser个实例然后随身携带在触发发送电子邮件的事件之前关联该关联。这种方法意味着我不会复制代码,但是我将类耦合在一起并且我打破了一些SOLID原则。我不确定,但我觉得这对测试来说也不是很好。

  2. 如上所述,创建一个服务类和方法来执行逻辑,但是我会编写逻辑来创建ClientUser实例,而不是使用其他两个服务,执行关联并触发事件发送电子邮件。这种方法感觉更好,我的代码更松散耦合,我没有违反任何SOLID原则,但是,我可能会复制代码。

  3. 简单地将我在ClientInterestService::createClientAndUser(...)中的逻辑放在我的控制器中。这样做意味着我的控制器中存在业务逻辑,这会破坏服务的重点。

2 个答案:

答案 0 :(得分:1)

对我来说最合适的是你提出的#2解决方案。

我喜欢做的是构建两个服务类,看看有什么重复,然后重构/提取任何重复到另一个类。这样,所有类都是非常可测试的,并且您最不可能违反任何SOLID原则。

答案 1 :(得分:1)

我认为如果你把它分解成更小的步骤,你就可以实现DRY架构。我看到的步骤是:

  • 创建客户端
  • 创建用户
  • 关联(通过数据透视表,联结表等)
  • 电子邮件

为避免出现可怕的重复代码,您需要在服务类或类中创建一个方法。然后,您将根据这些方法创建一个封装所涉及的所有步骤的操作。

不要害怕在服务类之外实现 - 这并不意味着它不在服务层之外。

我将客户利益注册为一项行动。您按照同步步骤来实现所需的操作。因此,基于创建用户,客户端等方法,我们可以构建一个注册客户端兴趣的操作,如下所示:

<?php

class ClientService {

public function addAction(IAction $action)
{
  return $action->process();
}

public function createUser() {} // business logic for creating a user.

public function createClient() {} // business logic for creating a client.

public function createAssociation() {} // business logic for creating an association.

} 

interface IAction {

  public function process();

}

class RegisterClientInterestAction implements IAction {

  protected $client; 

  public function __construct(ClientService $client)
  {
    $this->client = $client; 
  }

  public function process()
  {
    $this->createUser()->createClient()->createAssociation();
  }

  private function createUser() {} // interact with your client service to call the method $client->createUser()

  private function createClient() {} // interact with your client service to call the method $client->createClient()

  private function createAssociation() {} // interact with your client service to call the method $client->createAssociation()

}

//USAGE

$service  = new ClientService; 
$results  = $service->addAction(new RegisterClientInterestAction($service));

?> 

通过这种方式,您可以在新操作中使用createUser等方法,但无需复制代码。通过在服务类上使用addAction,您仍然在服务层内执行业务逻辑。

如果需要两项或更多项服务,我会采取稍微不同的方法,将execute行动转移到<?php class Service { public function addAction(IAction $action) { return $action->process(); } // Other stuff for a base service... } class UserService extends Service { public function createUser() {} // business logic for creating a user. } class ClientService extends Service { public function createClient() {} // business logic for creating a client. public function createAssociation() {} // business logic for creating an association. } interface IAction { public function process(); } class RegisterClientInterestAction implements IAction { protected $client; protected $service; public function __construct(ClientService $client, UserService $user) { $this->user = $user; $this->client = $client; } public function process() { $this->createUser()->createClient()->createAssociation(); } private function createUser() {} // interact with your user service to call the method $client->createUser() private function createClient() {} // interact with your client service to call the method $client->createClient() private function createAssociation() {} // interact with your client service to call the method $client->createAssociation() } //USAGE $service = new Service; $results = $service->addAction(new RegisterClientInterestAction(new ClientService, new UserService)); ?>

在处理多个服务方面,您可以在操作的构造函数中使用DI。

像这样:

undefined reference to