您如何处理依赖较多的服务和依赖注入?

发布于 2024-11-16 08:52:48 字数 864 浏览 0 评论 0原文

我正在将依赖注入与类似 SOA 的应用程序结合使用。

例如,我有一个 VoteService,用于为文章和评论投票。

然后我有 4 个依赖项:文章、评论、数据库抽象层和投票所需的用户。

所以我的构造函数有 4 个参数需要填充来获取我的对象。

我总是听说超过 2/3 的参数是对糟糕的代码设计的警告,我可能同意这一点。

也许我的 VoteService 设计得不好。

我可能不得不改变文章和文章中的投票。评论服务?

你怎么认为?


class ArticleService {
  public function createArticle(); // and other crud methods
}

class VoteService {

  public function __construct($entityManager, $articleService, $commentService, $configurationService);

  // here is the constructor with much arguments

  public function addArticleVote()
  {
     $vote = new ArticleVote();
     $vote->setType(ArticleVote::TYPE_UP)
     $vote->setArticle($article);
     $this->entityManager->persist($vote);
     $this->entityManager->flush();
  }

   // the same method applies for comment
}

I'm using Dependency Injection with a SOA-like application.

For example, I've a VoteService which is used to cast votes for both Article and Comment.

I've then 4 dependencies, Article, Comment, Database Abstraction Layer, and User which is required to cast votes.

So my constructor has 4 arguments to fill in to get my object.

I always heard that more than 2/3 arguments is a warning of bad code design, and I may agree with that.

Maybe my VoteService is then not well designed.

I may have to move the vote casting in both Article & Comment Service?

What do you think?


class ArticleService {
  public function createArticle(); // and other crud methods
}

class VoteService {

  public function __construct($entityManager, $articleService, $commentService, $configurationService);

  // here is the constructor with much arguments

  public function addArticleVote()
  {
     $vote = new ArticleVote();
     $vote->setType(ArticleVote::TYPE_UP)
     $vote->setArticle($article);
     $this->entityManager->persist($vote);
     $this->entityManager->flush();
  }

   // the same method applies for comment
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

永言不败 2024-11-23 08:52:48

我总是听说超过 2/3 的参数是代码设计不良的警告

这本身并不是一个问题。它只是潜在问题的一个指标。

而且这条规则通常适用于公共成员函数,而不适用于构造函数。

如果盲目应用这样的经验法则可能会很危险。你可能有问题,也可能根本没有问题。

您的架构中可能存在(或可能不)的一些问题示例:

  • 您的投票服务做得太多,应该进行拆分
  • 您的“投票服务”实际上并不是它自己的逻辑概念,只是系统中其他概念的一个方面
  • 您缺少概念的抽象(在本例中是投票,其中包含文章、评论和用户)

但我确实需要查看更多代码告诉您其中是否适用。从您的简短描述来看,您的服务听起来很简单,并且您对问题的思考过多。

我正在将依赖注入与类似 SOA 的应用程序一起使用。

在 SOA 应用程序中,您将具有用户不应该知道的依赖项。不要将它们暴露给用户。在这种情况下,用户不应该知道 DAL。

解决此问题的一种方法是采用应用程序的顶层(您要注入顶层依赖项的一层),在其上添加一个填充程序,并且仅向用户公开该填充程序。

请参阅外观模式

编辑:

例如,我有一个 VoteService,用于为文章和评论投票。 ...所以我的构造函数有 4 个参数需要填写来获取我的对象。

依赖注入不仅仅是构造函数注入。您还可以通过属性(或 setter 函数)以及在每个方法调用期间注入依赖项。您应该使用对每个依赖项有意义的任何一个。

您是否总是同时对文章和评论进行投票?您是否总是对同一篇文章和/或同一条评论进行投票?我的猜测是否定的,所以不要在构造函数中传递它们。

仅传递那些在构造函数中的使用之间不会更改的依赖项。将每次使用时都会更改的依赖项传递到函数的参数列表中。通过属性/设置器传递可选依赖项。

在您的特定情况下,您可能应该在构造函数中采用 $entityManager ,在构造函数或 setter 中采用 $configurationService (取决于它是否可以在没有依赖项),在 addArticleVote 方法中获取 $articleService,在 addCommentVote 方法中获取 $commentService

class VoteService {

  public function __construct($entityManager);

  // Adding this in case you have sensible logic if it isn't present.
  // If it isn't optional (you don't have defaults that make sense to put in this class),
  // then put it back in the ctor
  public function setConfigurationService($configurationService)
  {
    // ...
  }

  public function addArticleVote($articleService) // or $article
  {
    // ...
  }

  public function addCommentVote($commentService) // or $comment
  {
    // ...
  }
}

也许我的 VoteService 设计得不好。

我会评估您是否应该拥有 VoteService。例如,在 ArticleServiceCommentService 类上甚至在 Article 上添加 vote 方法可能是有意义的或您尚未描述的 Comment 类。

如果您对这种类型的反馈感兴趣(了解应该如何重构整个类集),那么您应该在 http:// codereview.stackexchange.com

I always heard that more than 2/3 arguments is a warning of bad code design

This is not a problem in-and-of itself. It is just an indicator of potential problems.

And this rule is usually applicable to public member functions, not to constructors.

Rules of thumb like this can be dangerous if you apply them blindly. You might have a problem, and you might have no problem at all.

Some examples of problems that might (or might not) exist in your architecture:

  • Your vote service is doing too much, and should be split up
  • Your "vote service" isn't actually its own logical concept, and just an aspect of other concepts in your system
  • You are missing an abstraction of a concept (in this case, a vote, which contains an article, comment, and user)

But I'd really have to see a lot more of your code to tell you if any of them apply. From your short description, it sounds like your service is simple, and that you're over-thinking the problem.

I'm using Dependency Injection with a SOA-like application.

In an SOA application, you will have dependencies that users shouldn't know about. Don't expose them to the users. In this case, users should not know about the DAL.

One way to solve this is to take your application's top layer (the one where you're injecting top-level dependencies), add a shim on top of that, and only expose the shim to the user.

See the Facade Pattern.

Edit:

For example, I've a VoteService which is used to cast votes for both Article and Comment. ... So my constructor has 4 arguments to fill in to get my object.

Dependency injection isn't only constructor injection. You can also inject dependencies through properties (or setter functions), and during each method call. You should use whichever makes sense for each dependency.

Are you always voting on both an article and a comment at the same time? Are you always voting on the same article and/or same comment? My guess is no, so don't pass them in the constructor.

Pass only those dependencies that won't change between uses in the constructor. Pass those dependencies that change on each use in a parameter list in your function. Pass optional dependencies via properties/setters.

In your particular case, you should probably take the $entityManager in the constructor, take the $configurationService either in the constructor or in a setter (depending on if it can live without the dependency), take the $articleService in the addArticleVote method, and take the $commentService in the addCommentVote method.

class VoteService {

  public function __construct($entityManager);

  // Adding this in case you have sensible logic if it isn't present.
  // If it isn't optional (you don't have defaults that make sense to put in this class),
  // then put it back in the ctor
  public function setConfigurationService($configurationService)
  {
    // ...
  }

  public function addArticleVote($articleService) // or $article
  {
    // ...
  }

  public function addCommentVote($commentService) // or $comment
  {
    // ...
  }
}

Maybe my VoteService is then not well designed.

I'd evaluate whether you should even have a VoteService. It might make sense to add vote methods on the ArticleService and CommentService classes, for example, or even on Article or Comment classes that you haven't described.

If you're interested in feedback of this type (seeing how you should refactor your whole set of classes), then you should post another question on http://codereview.stackexchange.com

树深时见影 2024-11-23 08:52:48

总是听说超过 2/3 的参数是代码设计不良的警告

完全错误。尤其是在这种情况下。
你正在以正确的方式做这件事(DI)。我认为这里不需要更改。

我可能不得不改变文章和文章中的投票。评论服务?

这可能是另一种解决方案。但在我看来,你可以自由地和这个在一起。
如果您想实现此解决方案,您可以使用 addVote 方法创建一个接口 IVotable

此时,您可以在 Articles/Comments 类中实现此接口,这样您就可以执行以下操作:

$a = new Article;
$b = new Comment;
$a->addVote($currentLoggedUser,10); //> Inject only loggedUser (and maybe your DAL)
$b->addVote($currentLoggedUser,10);

always heard that more than 2/3 arguments is a warning of bad code design

Completly false. Especially in this case.
You are doing it the right way (DI). No need for changes here imo.

I may have to move the vote casting in both Article & Comment Service?

This could be another solution. But you can freely stay with this imo.
If you want implement this solution you can create an interface IVotable with a method addVote.

At this point you can implements this interface in your Articles/Comments class so you could do:

$a = new Article;
$b = new Comment;
$a->addVote($currentLoggedUser,10); //> Inject only loggedUser (and maybe your DAL)
$b->addVote($currentLoggedUser,10);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文