Laravel 模式 - 工作与服务的使用
Laravel patterns - Usage of jobs vs services
我想知道大多数开发人员如何使用这两个 Laravel 工具。
在 Laravel 中,您可以使用服务或作业处理业务逻辑(我们只讨论不可排队的作业,只讨论那些 运行在同一个过程中)。
例如,用户想要创建一个实体,比方说一本书,您可以使用服务或调度作业来处理实体创建。
使用作业会是这样的:
class PostBook extends Job
{
...
public function handle(Book $bookEntity)
{
// Business logic here.
}
...
}
class BooksController extends Controller
{
public function store(Request $request)
{
...
dispatch(new PostBook($request->all()));
...
}
}
使用服务,它会是这样的:
class BookService
{
public function store(Request $request)
{
// Business logic here.
}
}
class BooksController extends Controller
{
public function store(Request $request)
{
...
// I could inject the service instead.
$bookService = $this->app()->make(App\Services\BookService::class);
$bookService->store($request);
...
}
}
问题是,您通常如何选择使用一种方式或另一种方式?为什么?
在这件事上肯定有两个"schools",但我想了解每一个的优缺点。
"Business logic" 可以用 任何东西 处理,所以看起来真正要问的是哪个选项更适合重复相同的业务逻辑 不重复代码.
A Job class 通常会做 一件事情 ,正如它的 handle()
方法所定义的那样。很难从比较中排除排队的作业,因为 运行 它们同步通常违背了处理缓慢、昂贵或不可靠的操作(例如调用网络 API)的目的 在 当前请求已完成并向用户显示响应后。
如果所有作业都应该是同步的,那么它与为您的业务逻辑定义一个 函数 没什么不同。这实际上与分派同步作业的作用非常接近:在调用堆栈的某个位置,它最终 运行 call_user_func([$job, 'handle'])
调用您作业上的单个方法 object。更重要的是,同步作业缺少重试 可能由于网络故障等外部原因而失败的作业的机制。
另一方面,服务是围绕组件封装逻辑的简单方法,它们可能会不止一件事。在这种情况下,组件可以被认为是您的应用程序的一部分,可以换出不同的实现而无需修改使用它的代码。框架中包含的一个完美示例是 Filesystem
服务(最常通过 Storage
门面访问)。
考虑一下您是否没有通过将书籍插入数据库来存储书籍,而是通过发布到外部 API。你可能有一个 BookRepository service,它不仅有一个 store()
方法,还有一个 get()
, update()
, list()
, delete()
,或任意数量的其他方法。所有这些请求都共享用于向外部 Web 服务进行身份验证的逻辑(例如向请求添加 headers),并且您的 BookRepository class 可以封装该 re-usable 逻辑。您可以在计划的 artisan 命令、Web 控制器、api 控制器、作业、中间件等内部使用此服务 class — 无需重复代码。
使用此示例,您可以创建一个 Job 来存储一本新书,这样您就不会在 API 响应缓慢时让用户等待(而且它失败时可以重试)。在内部,您的作业在运行时会调用您的 Service 的 store()
方法。服务完成的工作由作业安排。
我想知道大多数开发人员如何使用这两个 Laravel 工具。
在 Laravel 中,您可以使用服务或作业处理业务逻辑(我们只讨论不可排队的作业,只讨论那些 运行在同一个过程中)。
例如,用户想要创建一个实体,比方说一本书,您可以使用服务或调度作业来处理实体创建。
使用作业会是这样的:
class PostBook extends Job
{
...
public function handle(Book $bookEntity)
{
// Business logic here.
}
...
}
class BooksController extends Controller
{
public function store(Request $request)
{
...
dispatch(new PostBook($request->all()));
...
}
}
使用服务,它会是这样的:
class BookService
{
public function store(Request $request)
{
// Business logic here.
}
}
class BooksController extends Controller
{
public function store(Request $request)
{
...
// I could inject the service instead.
$bookService = $this->app()->make(App\Services\BookService::class);
$bookService->store($request);
...
}
}
问题是,您通常如何选择使用一种方式或另一种方式?为什么?
在这件事上肯定有两个"schools",但我想了解每一个的优缺点。
"Business logic" 可以用 任何东西 处理,所以看起来真正要问的是哪个选项更适合重复相同的业务逻辑 不重复代码.
A Job class 通常会做 一件事情 ,正如它的 handle()
方法所定义的那样。很难从比较中排除排队的作业,因为 运行 它们同步通常违背了处理缓慢、昂贵或不可靠的操作(例如调用网络 API)的目的 在 当前请求已完成并向用户显示响应后。
如果所有作业都应该是同步的,那么它与为您的业务逻辑定义一个 函数 没什么不同。这实际上与分派同步作业的作用非常接近:在调用堆栈的某个位置,它最终 运行 call_user_func([$job, 'handle'])
调用您作业上的单个方法 object。更重要的是,同步作业缺少重试 可能由于网络故障等外部原因而失败的作业的机制。
服务是围绕组件封装逻辑的简单方法,它们可能会不止一件事。在这种情况下,组件可以被认为是您的应用程序的一部分,可以换出不同的实现而无需修改使用它的代码。框架中包含的一个完美示例是 Filesystem
服务(最常通过 Storage
门面访问)。
考虑一下您是否没有通过将书籍插入数据库来存储书籍,而是通过发布到外部 API。你可能有一个 BookRepository service,它不仅有一个 store()
方法,还有一个 get()
, update()
, list()
, delete()
,或任意数量的其他方法。所有这些请求都共享用于向外部 Web 服务进行身份验证的逻辑(例如向请求添加 headers),并且您的 BookRepository class 可以封装该 re-usable 逻辑。您可以在计划的 artisan 命令、Web 控制器、api 控制器、作业、中间件等内部使用此服务 class — 无需重复代码。
使用此示例,您可以创建一个 Job 来存储一本新书,这样您就不会在 API 响应缓慢时让用户等待(而且它失败时可以重试)。在内部,您的作业在运行时会调用您的 Service 的 store()
方法。服务完成的工作由作业安排。