了解 IoC、DI 和参考方法
我正在学习依赖注入和控制反转,我想我开始理解这是如何工作的:
- 对象不应该关心自己依赖项的创建
- 依赖项应该传递给对象(通过构造函数或 setter 方法)
- DI 容器可以完成创建具有所有所需依赖项的对象的工作
如果这一切都是正确的,我可以不再在我的对象中使用所谓的“引用方法”吗?
这就是我所说的参考方法。假设我有两个针对家庭和家庭成员的模型。我发现创建引用与该模型相关的对象的方法非常有帮助。在下面的示例中,当调用 $family->members()
时,我可以快速访问所有家庭成员。但是,这意味着我的 family
对象正在实例化 family_member
类......这是否违反了 IoC 规则?
如果 family_member
类具有超出 family
类范围的依赖项怎么办?在此输入将非常感激!
<?php
class family
{
public $id;
public function members()
{
// Return an array of family_member objects
}
}
class family_member
{
public $family_id;
public $first_name;
public $last_name;
public $age;
}
I'm in the process of learning depenency injection and inversion of control, and I think I'm starting to understand how this works:
- Objects should not concern themselves with the creation of their own dependencies
- Dependencies should be passed to the object (via the constructor or setter methods)
- A DI container can do the work of creating objects with all of their required dependencies
If this is all correct, can I no longer use what I call "reference methods" in my objects?
Here is what I mean by reference methods. Say I have two models for families and family members. I find it very helpful to create methods that reference objects that relate to that model. In the example below, when calling $family->members()
, I can quickly gain access to all the family members. But, this would mean that my family
object is instantiating family_member
classes...and doesn't this break the rules of IoC?
What if the family_member
class had a dependency that was outside of the scope of the family
class? Input here would be much appriciated!
<?php
class family
{
public $id;
public function members()
{
// Return an array of family_member objects
}
}
class family_member
{
public $family_id;
public $first_name;
public $last_name;
public $age;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
免责声明:我只是自己学习 DI。对这个答案持保留态度。
依赖注入只是注入依赖。如果您的面向对象设计导致
Family
对象有责任创建Member
实例,那么无论如何,让Family
对象创建Member
,因为在这种情况下,Member
不再被视为Family
的依赖项,而是一个责任。。因此:但是如果你想一想,Family真的应该有创建
Member
的责任吗?更好的设计是有另一个对象,例如FamilyMapper
创建Family
及其成员。像这样:使用此模式,您的域对象及其方法(可能包含业务逻辑)将与您的数据访问代码解耦。这就是依赖注入的好处——它迫使你重新思考你的面向对象设计,这样你最终会得到更清晰的代码。
很多人认为使用依赖注入就意味着不使用工厂之类的。 这是错误的!依赖注入只是注入依赖项。您也可以对工厂对象使用依赖项注入,通过将依赖项注入工厂而不是让工厂实例化自己的依赖项。
有用的链接:
补充
再次强调,对下面的内容持保留态度。
另请注意,依赖注入和依赖注入容器之间存在差异。第一个是注入依赖项的简单概念,而不是让对象自己创建它(这会导致非常高的耦合)。我们从上面的例子中看到了这一点。
后者是处理依赖项注入的框架/库的术语,因此您不必进行手动注入。容器的职责是连接依赖关系,因此您不必做肮脏的工作。这个想法是您定义一个依赖项注入配置,它告诉容器
Foo
对象有哪些依赖项,以及如何注入它们。容器会读取文档并为您执行注入。这就是 Pimple、SimpleDIC 等 DIC 库所做的事情。您可以将依赖注入容器与工厂进行比较,因为两者都是创建对象,其唯一职责是创建对象。虽然工厂通常是专门化的(即
FamilyMemberFactory
创建MemberInterface
的实例),但依赖项注入容器更为通用。有人说使用依赖注入容器可以减轻您对工厂的需求,但您应该记住,这意味着您必须创建和维护依赖注入配置文件,这可能是数千个 XML/PHP 行。我希望这有帮助。
Disclaimer: I'm just learning DI myself. Take the answer with a grain of salt.
Dependency injection is only about injecting dependencies. If your object oriented design results in
Family
object having the responsibility to create instances ofMember
, then by all means, have theFamily
object create theMember
, because in that case,Member
is no longer considered a dependency ofFamily
, but a responsibility. Therefore:But if you think about it, does
Family
really should have the responsibility of creatingMember
? A better design is to have another object, such asFamilyMapper
createFamily
along with its members. Like this:Using this pattern, your domain objects, along with their methods (which may contain business logic) will be decoupled from your data access code. That's the good thing about dependency injection - it forces you to rethink your OO design, so that you end up with cleaner code.
Many people think that using dependency injection means not using factories and such. This is wrong! Dependency injection is only about injecting dependencies. You can use dependency injection with factory objects too, by injecting dependencies to the factory instead of having the factory instantiating its own dependency.
Useful links:
Additions
Again, take the stuff below here with a grain of salt.
Please also note that there is a difference between dependency injection and dependency injection container. The first one is a simple concept of injecting dependencies instead of having objects creating it themselves (which results in very high coupling). We see this from the example above.
The latter is a term for frameworks/libraries that deal with dependency injection so you don't have to do manual injection. The container's responsibility is wiring dependencies so you don't have to do the dirty work. The idea is you define a dependency injection configuration, which tells the container what dependencies
Foo
object has, and how to inject them. The container reads the documentation and performs the injection for you. This is what DIC libraries like Pimple, SimpleDIC do.You can compare dependency injection containers with factories, since both are a creational objects, whose sole responsibility is to create objects. While factories are often specialized (i.e.
FamilyMemberFactory
creating instances ofMemberInterface
), dependency injection container is more general. Some people say using dependency injection container relieves you of the need for factories, but you should remember that it means you have to create and maintain dependency injection configuration files, which could be thousands of XML/PHP lines.I hope this helps.
虽然您可以仅使用依赖注入并一直使用,但在我看来,尝试在设计中找到平衡同时保持其可维护性是一种更明智的方法。
因此,依赖注入和工厂的结合将使您的生活变得更加轻松。
工厂模式在某种程度上与控制反转和依赖注入兼容。虽然依赖项注入使您的对象免于创建其依赖项,但工厂模式允许它创建依赖项的基本实现。最后,它仍然允许您在需要时覆盖对象依赖项:
这在测试时特别有用:
依赖项注入很棒,但它不能解决您所有的设计问题。当然,它们是不可互换的。工厂模式可以做 DI 不能做的事情,反之亦然。
While you can go with dependency injection only and all the way, trying to find a balance in your design while keeping it maintainable is a more sane approach, in my opinion.
As such, a combination of dependency injection and factories will make your life much easier.
The factory pattern is somewhat compatible with inversion of control and dependency injection. While dependency injection frees your object from creating its dependencies, the factory pattern lets it create a base implementation of a dependency. And in the end, it still allows you to override object dependencies when required:
This is especially useful when testing:
Dependency injection is great, but it cannot solve all your design problems. Of course, they are not interchangeable. The factory pattern do things DI can't and vice-versa.
问题在于 DI 背后的整个想法是
Family
不应该知道如何创建特定的FamilyMember
,例如,您应该有一个IFamilyMember
> 它的实现可能会因应用程序的每个模块/层而异。应该是这样的:
基本上,一切都归结为组件应该不知道其依赖关系,在您的情况下,
Family
依赖于FamilyMember
,所以任何< code>FamilyMember 实现需要从 Family 本身中抽象出来。对于 PHP 的具体情况,请考虑查看 Symfony,它大量使用了 DI 模式,或者您也可以考虑使用 Symfony 依赖注入框架,它是 Symfony 的一部分,但可以用作一个单独的组件。 Fabien Potencier 还针对此事撰写了一篇不错的文章。
希望我能帮忙!
The problem is that the whole idea behind DI is that
Family
should not know how to create a specificFamilyMember
, for instance, you should have anIFamilyMember
and implementations for it may vary on each module / layer of your application.Should be something like this:
Basically, everything sums up to the idea that components should be ignorants of their dependencies, and in your case,
Family
depends onFamilyMember
, so anyFamilyMember
implementation needs to be abstracted from the Family itself.For the specific case of PHP, consider checking out Symfony, which does heavy use of the DI pattern or you can consider using the Symfony Dependency Injection framework, which is a part of Symfony, but can be used as a separate component. Also Fabien Potencier has written a nice article on the matter.
Hope I can help!