jjzjj

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

coder 2024-04-18 原文

在我的项目中,我决定使用服务模式(可能还有存储库模式)来处理我的应用程序中的业务逻辑。例如,我有一个 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创建 Client 的类和 User实例,然后在触发发送电子邮件的事件之前执行关联。这种方法意味着我不是在复制代码,而是将类耦合在一起并且我打破了一些 SOLID 原则。我不确定,但我觉得这也不适合测试。

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

  3. 简单地把我本应拥有的逻辑放在ClientInterestService::createClientAndUser(...)中在我的 Controller 中。这样做意味着我的 Controller 中有业务逻辑,这在某种程度上破坏了提供服务的意义。

最佳答案

我认为,如果将其分解为更小的步骤,就可以实现 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));

?>

关于php - Laravel:服务/存储库模式和复制代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37727003/

有关php - Laravel:服务/存储库模式和复制代码的更多相关文章

  1. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  4. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  5. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  6. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  7. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  8. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  9. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  10. ruby-on-rails - 浏览 Ruby 源代码 - 2

    我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

随机推荐