在我的项目中,我决定使用服务模式(可能使用存储库模式)来处理应用程序中的业务逻辑.我有一个客户端模型,它代表一个客户和一个相应的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));
?>