您如何处理依赖较多的服务和依赖注入?
我正在将依赖注入与类似 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这本身并不是一个问题。它只是潜在问题的一个指标。
而且这条规则通常适用于公共成员函数,而不适用于构造函数。
如果盲目应用这样的经验法则可能会很危险。你可能有问题,也可能根本没有问题。
您的架构中可能存在(或可能不)的一些问题示例:
但我确实需要查看更多代码告诉您其中是否适用。从您的简短描述来看,您的服务听起来很简单,并且您对问题的思考过多。
在 SOA 应用程序中,您将具有用户不应该知道的依赖项。不要将它们暴露给用户。在这种情况下,用户不应该知道 DAL。
解决此问题的一种方法是采用应用程序的顶层(您要注入顶层依赖项的一层),在其上添加一个填充程序,并且仅向用户公开该填充程序。
请参阅外观模式。
编辑:
依赖注入不仅仅是构造函数注入。您还可以通过属性(或 setter 函数)以及在每个方法调用期间注入依赖项。您应该使用对每个依赖项有意义的任何一个。
您是否总是同时对文章和评论进行投票?您是否总是对同一篇文章和/或同一条评论进行投票?我的猜测是否定的,所以不要在构造函数中传递它们。
仅传递那些在构造函数中的使用之间不会更改的依赖项。将每次使用时都会更改的依赖项传递到函数的参数列表中。通过属性/设置器传递可选依赖项。
在您的特定情况下,您可能应该在构造函数中采用
$entityManager
,在构造函数或 setter 中采用$configurationService
(取决于它是否可以在没有依赖项),在addArticleVote
方法中获取$articleService
,在addCommentVote
方法中获取$commentService
。我会评估您是否应该拥有
VoteService
。例如,在ArticleService
和CommentService
类上甚至在Article
上添加vote
方法可能是有意义的或您尚未描述的Comment
类。如果您对这种类型的反馈感兴趣(了解应该如何重构整个类集),那么您应该在 http:// codereview.stackexchange.com
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:
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.
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:
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 theaddArticleVote
method, and take the$commentService
in theaddCommentVote
method.I'd evaluate whether you should even have a
VoteService
. It might make sense to addvote
methods on theArticleService
andCommentService
classes, for example, or even onArticle
orComment
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
完全错误。尤其是在这种情况下。
你正在以正确的方式做这件事(DI)。我认为这里不需要更改。
这可能是另一种解决方案。但在我看来,你可以自由地和这个在一起。
如果您想实现此解决方案,您可以使用
addVote
方法创建一个接口IVotable
。此时,您可以在
Articles/Comments
类中实现此接口,这样您就可以执行以下操作:Completly false. Especially in this case.
You are doing it the right way (DI). No need for changes here imo.
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 methodaddVote
.At this point you can implements this interface in your
Articles/Comments
class so you could do: