php – Laravel:服务/存储库模式和重复代码

在我的项目中,我决定使用服务模式(可能使用存储库模式)来处理应用程序中的业务逻辑.我有一个客户端模型,它代表一个客户和一个相应的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并创建一个客户端,一个用户,将两者关联起来,最后向新用户发送一封带有详细信息的电子邮件.

哪里,在使用服务模式时最好放这个逻辑?

我考虑过:

>创建一个服务和方法ClientInterestService :: createClientAndUser(…),它将使用ClientService和UserService类创建客户端和用户实例,然后在触发发送电子邮件的事件之前执行关联.这种方法意味着我不会复制代码,但是我将类耦合在一起并且我打破了一些SOLID原则.我不确定,但我有一种感觉,这也不适合测试.
>如上所述,创建一个服务类和方法来执行逻辑,但不是使用其他两个服务,而是编写逻辑来创建客户端和用户实例,执行关联并触发事件以发送电子邮件.这种方法感觉更好,我的代码更松散耦合,我没有违反任何SOLID原则,但是,我可能会复制代码.
>简单地将我在ClientInterestService :: createClientAndUser(…)中的逻辑放在我的控制器中.这样做意味着我的控制器中存在业务逻辑,这会破坏服务的重点.

最佳答案 我想如果你把它分解成更小的步骤,你就可以实现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,您仍然在服务层内执行业务逻辑.

如果需要两个或更多服务,我会采取稍微不同的方法移动我执行操作的位置.

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

像这样:

<?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));

?>
点赞