控制器逻辑与服务/业务层逻辑

Posted

技术标签:

【中文标题】控制器逻辑与服务/业务层逻辑【英文标题】:Controller logic vs Service/Business layer logic 【发布时间】:2017-08-08 00:40:40 【问题描述】:

我正在开发一个应用程序,并且正在为 REST API 使用 Repository-Service-Controller 方法。

我发现自己在控制器逻辑与服务逻辑之间争论不休。服务逻辑处理业务逻辑,例如计算图书价格,而控制器逻辑处理表示细节。

如果部分业务逻辑的 应用程序是检查发布者是否订阅了 PremiumService 确定这本书是否可编辑?将 这是业务逻辑还是控制器逻辑? 如果在控制器中,如果出版商未在PremiumService 中订阅,我想隐藏正在呈现的书籍怎么办? PremiumService 是否会成为 PublisherController 的依赖项,以检查图书的出版商是否在 PremiumService 中订阅?

我可以看到在 BookService 上创建过多的依赖项会变成意大利面条式代码。

这是一个带有伪代码的界面,可以帮助回答我的问题。

class Publisher

    public function getId(): int;
    public function getName(): string;
    public function getBooks(): Book[];



class Book

    public function getId(): int;
    public function getName(): string;
    public function getPublisher(): Publisher;
    public function getAuthors(): Author[];


class Author

    public function getId(): int;
    public function getName(): string;
    public function getBooks(): Book[];


// Simple CRUD repository.
class BookRepository

    public function find($id);
    public function findAll($criteria);
    public function create($book);
    public function edit($book);
    public function remove($book);


class BookService

    public function __construct(
        BookRepository $book_repository,
        AuthorService $author_service,
        PremiumService $subscription_service
    );

    public function get($id);

    public function getAll($criteria);

     // Book is editable if the publisher of the book is subscribed to the PremiumService
    public function edit(Book $book);

    // Book is removable if the publisher of the book is subscribed to the PremiumService
    public function remove(Book $book);

    // Can only add an author if the publisher of the book is subscribed to the PremiumService.
    public function addAuthor(Author $author, Book $book);


class PublisherController

    public function __construct(BookService $book_service);

    // Can only view a book if the publisher of the book is subscribed to the PremiumService
    public function getBook(Request $request);

    // Can only view books if the publisher of the book is subscribed to the PremiumService
    public function getBooks(Request $request);

如果一个服务依赖于其他服务的太多依赖项,这里通常或推荐的方法是什么?服务应该像存储库一样愚蠢吗?

【问题讨论】:

【参考方案1】:

回答您的问题:

1) 你回答了你自己的问题,说“如果应用程序的部分业务逻辑是......”既然是业务逻辑,就把它放在业务逻辑层(即服务)。

2) 如果出版商未订阅订阅服务,则隐藏书籍听起来像是您业务逻辑的一部分(您的业务规则是,如果用户不付费,他们就无法阅读书籍),因此会去服务。然后是的,该服务必须是您的控制器的依赖项。

我经常发现自己处于与您类似的情况,其中单个业务规则需要依赖于许多业务服务才能完成其工作。避免在您的服务中产生大量依赖项,同时保持每个服务简单的一个好方法是,一旦您开始获得一个服务的四个或五个依赖项,就使用 facade 服务。外观是一个更高级别的服务,负责协调较低级别的服务。

例如,您可以有一个 ContentManager 服务,它接受 BookServiceAuthorServicePremiumService 的依赖项。然后你的控制器只对ContentManager 有一个依赖。当您的控制器想要显示书籍列表时,它会调用 ContentManager.getBooks 并传入一些用户详细信息,以便您确定该用户是否已订阅。然后ContentManager判断用户是否可以查看一本书,获取该书的详细信息,获取该书的作者详细信息,等等。

尽管 ContentManager 最终在其子服务中包含很多东西,但它仍然是一个非常简单的类,因为它的唯一工作是为给定操作调用适当的子服务方法。

诚然,这对您的情况来说并不是一个很大的改进,因为您没有大量的依赖项,但是如果您发现自己处于需要控制器的情况,比如八个依赖项,那么您可以将它们分解为外观。如果其中五项服务用于一组高级业务规则(例如您的图书馆/出版商管理),而其中三项服务用于另一组高级业务规则(例如计费),那么您会一个门面有五个依赖项,另一个门面有三个依赖项。

【讨论】:

以上是关于控制器逻辑与服务/业务层逻辑的主要内容,如果未能解决你的问题,请参考以下文章

业务逻辑和数据访问层的循环依赖

Spring Boot 业务逻辑层

如果我从控制器中取出逻辑,是不是需要业务逻辑层?

CakePHP 业务逻辑层

3层架构业务逻辑层无逻辑

称为包含业务逻辑的应用程序服务