在我的项目中,我决定使用服务模式(可能使用存储库模式)来处理应用程序中的业务逻辑。我有一个代表客户的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
,将两者关联起来,最后发送一封电子邮件给带有详细信息的新用户。
在使用服务模式时,最好采用这种逻辑吗?
我考虑过:
创建一个服务和方法ClientInterestService::createClientAndUser(...)
,它将使用ClientService
和UserService
类创建Client
和User
个实例然后随身携带在触发发送电子邮件的事件之前关联该关联。这种方法意味着我不会复制代码,但是我将类耦合在一起并且我打破了一些SOLID原则。我不确定,但我觉得这对测试来说也不是很好。
如上所述,创建一个服务类和方法来执行逻辑,但是我会编写逻辑来创建Client
和User
实例,而不是使用其他两个服务,执行关联并触发事件发送电子邮件。这种方法感觉更好,我的代码更松散耦合,我没有违反任何SOLID原则,但是,我可能会复制代码。
简单地将我在ClientInterestService::createClientAndUser(...)
中的逻辑放在我的控制器中。这样做意味着我的控制器中存在业务逻辑,这会破坏服务的重点。
答案 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