害怕使用依赖注入框架
我一直在阅读依赖注入框架。我真的爱上了分离关注点并让对象完成其核心工作的想法 - 这无疑是一个优秀且长期存在的设计原则!
然而,我对 DI 框架了解得越多,我就越担心: 1)他们“自动”解决依赖关系的方式 2)关于配置文件中引入的极端复杂性
就第二点而言,我看到我的客户花费数百万美元来培训人们使用产品,其中重要的部分是如何“不”接触配置文件。管理员现在害怕这些配置文件。
尽管如此,我看到了另一种称为服务定位器的模式,我可以在应用程序开始时很好地组装我想要的所有“全局”服务(可能是应用程序主机或应用程序上下文或其他)。使该服务定位器在全球范围内可用,瞧!
然而,我发现当我需要基于某种标准(谁知道?)的不止一种类型的“全局”服务时,使用服务定位器方法的灵活性会降低!
所以,在这里我比以前更困惑该往哪个方向走。虽然我非常喜欢它的设计原理,但现有框架的复杂性让我望而却步!
我的担忧是真实的吗?还有其他人有同样的感觉吗?如果是这样,对于如此巨大的压倒性“框架”,有什么好的替代方案吗?
I have been reading up on Dependency Injection frameworks. I really fell in love with the idea of separating the concerns and letting the objects do their core work - which is undoubtedly an excellent and long-standing design principle!
However the more I read on DI frameworks, the more I get worried:
1) In the way they "automagically" resolve dependencies
2) About the extreme complexities being introduced in the configuration files
On just the point #2, I have seen my customers spend millions of dollars to train the people on products of which the significant part was how "not" to touch config files. The administrators are now dreading these config files.
Nevertheless, I see another pattern called Service Locators where I could nicely assemble all the "global" services that I want at the start of my application (may be an application host or app context or whatever). Make this service locator globally available and voila!
However I see that there will be less flexibility when using the Service Locator approach when I need more than one type of "global" service based on some criterion (known to whom?)!
So, here I am more confused than before on which direction to take. Though I like the design principle very much, the complexity in the existing frameworks are throwing me off!
Are my concerns genuine? Anybody else feel the same? If so, is there any good alternative for such massively overwhelming "frameworks"?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我个人非常喜欢使用 Autofac。容器配置是通过代码完成的,同时消除了冗长的 XML 并启用了重构支持。
不过,最好的功能之一是模块。它们是容器配置的单元,允许您管理组成应用程序的许多不同组件的复杂性。
我目前正在开发一个非常大的项目,体验与小型项目时大致相同,这意味着这种方法的扩展性非常好。
支持 DI 的类的一个主要原则是它们不引用基础结构代码。这是服务定位器模式的对立面。服务定位器的主要缺点是,除了增加引用容器的类的复杂性之外,还无法更改解析的依赖项的版本。
对于不引用容器的“纯”类,任何给定依赖项的解析版本都位于正在注入的类的外部。
I personally quite enjoy using Autofac. The container configuration is done through code, at the same time eliminating verbose XML and enabling refactoring support.
One of the best features, though, is modules. They are units of container configuration, allowing you to manage the complexity of the many different components which comprise your application.
I am currently working on a very large project, and the experience is roughly the same as when it was small, meaning this approach scales very well.
A main tenet of DI-enabled classes is that they do not reference infrastructure code. This is the antithesis of the Service Locator pattern. The main downfall of Service Locator is that, in addition to adding complexity to classes which reference the container, there is no ability to change which version of a dependency is resolved.
With "pure" classes that don't reference a container, the resolved version of any given dependency is external to the class being injected.
正如内特提到的,“魔法”是可选的;如果需要,您可以手动配置所有内容。
我最初(或永远!)会避免使用配置文件,并在代码中配置容器。这往往更容易阅读和维护。大多数时候您不需要即时更改配置。客户无法触及配置文件,因为它们不存在。
服务定位器也有缺点;其一,他们倾向于将您的类与定位器类/框架结合起来。一个好的 DI 框架会让你使用普通的旧对象;您的项目中可能只有一个实际使用 DI/IoC 框架的类。
StructureMap 和 Unity 都非常简单;尝试一下。从小处开始。
这是一个非常简单的 Unity 示例(包括内联配置):
As Nate mentioned, the "magic" is optional; you can configure everything by hand if you want.
I'd avoid the configuration files initially (or forever!) and configure the container in code. That tends to be much easier to read and maintain. Much of the time you don't need on-the-fly changes to configuration. Customers can't touch the configuration files because they don't exist.
Service locators have downsides; for one, they tend to couple your classes to the locator class/framework. A good DI framework will let you use Plain Old Objects; you may only have a single class in your project that actually uses the DI/IoC framework.
StructureMap and Unity are both pretty simple; give them a try. Start small.
Here's a really simple example with Unity (including inline configuration):
如果您确实考虑采用依赖注入路线,我强烈建议快速阅读 Martin Fowler 的优秀依赖注入文章:
http://martinfowler.com/articles/injection.html
我现在正在开发一个包含大量配置文件的 Java 项目。我们预先选择单例模式来表示我们的配置(有点类似于全局解决方案)。以下是让我发疯的事情,让我希望我们有一个依赖注入模式:
使用全球化模式进行单元测试很糟糕。依赖注入模式很容易进行单元测试,尤其是模拟对象测试。在单例类型的情况下,您现在拥有所有这些单元测试,但仍然需要可用的全局状态才能运行。通过依赖注入,您可以创建传递到测试中的特定于测试的模拟配置对象。我无法夸大这使得单元测试变得多么容易。另一篇题为“Endo-Testing:使用模拟对象进行单元测试”的优秀论文:http://connextra.com/ aboutUs/mockobjects.pdf
使用全球化的方法在较小的系统中效果更好,但随着线程数量的增长,它们都开始争夺配置资源。您可能会遇到同步问题,并且您的配置访问甚至可能开始成为瓶颈。这对我们来说还不是一个大问题,但它开始让我们所有人烦恼。
一旦你沿着非依赖注入路线走了一小段路,就没有真正的回头路了。从依赖注入到某种全球化模式很烦人,但在逐步的基础上是可行的。尝试从全球化模式回到依赖注入是一场噩梦。我一直想在我们的项目中这样做,但我做不到。这将需要整个开发周期。
不管怎样,希望这篇文章和经验能帮助你做出决定。我在你考虑的道路上还有很长的路要走,我有点希望我们能采取依赖注入路线:-D
If you're really thinking about going the Dependency Injection route, I highly recommend giving Martin Fowler's excellent dependency injection article a quick read:
http://martinfowler.com/articles/injection.html
I'm working on a Java project right now with lots of configuration files. We opted up-front for a Singleton pattern to represent our configuration (somewhat analagous to a global solution). Here's the things that drive me insane and make me wish we had a Dependency Injection pattern instead:
Unit testing with globalized patterns sucks. Dependency Injection patterns lend themselves readily to easier unit testing and especially mock object testing. In the singleton-type case, you now have all these unit tests that still need a global state available in order to run. With dependency injection, you can make test-specific mock configuration objects that you pass into your tests. I can't overstate how much easier this makes unit testing. Another excellent paper entitled "Endo-Testing: Unit Testing with Mock Objects": http://connextra.com/aboutUs/mockobjects.pdf
Using a globalized sort of approach works better in smaller systems, but as your numbers of threads grows, they all begin to compete for the configuration resources. You can run into synchronization issues and your configuration accesses can even start to become a bottleneck. This hasn't been a huge problem for us yet, but it's beginning to annoy us all.
Once you go a little ways down a non-dependency injection route, there's no real going back. Going from dependency injection to some sort of globalized pattern is annoying, but doable on a sort of step-by-step basis. Trying to go from a globalized pattern back to dependency injection is a nightmare. I keep wanting to do it on our project and I just can't. It would take an entire development cycle.
Anyway, hope the article and the experience help you make a decision. I'm a long ways down the path you're thinking about heading down and I kinda wish we would've taken the dependency injection route instead :-D
这些都不是 DI“必需的”——它们是某些 DI 框架提供的选项。就我个人而言,我也不喜欢“自动”注入 - 我可以看到它适用于非常小的项目,但会在较大的项目上引起问题。对于第 2 点 - 我不确定我是否明白这一点 - 我主要使用 Spring。 Spring 提供 XML 和 Java 配置选项。它提供嵌套配置。如果配置的一部分您不希望任何人更改,而另一部分您却需要更改(将它们分成单独的配置文件),或者将一个 XML 和另一个 Java 设为“可更改”。 Spring 还支持使用属性文件中的值,这就是我希望管理员更改的所有内容 - 管理员不是程序员 - 他们不应该“重新连接”您的应用程序 - 只是提供适当的选项。
Neither of these are "required" for DI - they are options supplied by some DI frameworks. Personally, I dislike the "automagic" injection too - I can see it working for really small projects, but causing problems on larger projects. For point #2 - I'm not sure I get the point - I've mostly used Spring. Spring provides both XML and Java configuration options. It provides nested configurations. If there's a part of the configuration that you don't want anyone to change and there's a part that you do - separate them into separate configuration files - or make the "changeable" one XML and the other Java. Spring also supports using values from property files which is all that I'd expect administrators to change - administrators aren't programmers - they shouldn't be "re-wiring" your app - just providing appropriate options.
根据您使用的语言,有些 DI 框架并不那么可怕,尽管您会有一些配置文件,但它们不应该是可怕的,而是有用的。
例如,我有一个用于开发的配置文件,一个用于测试,一个用于生产。
因此,根据我使用的数据库连接可以更改,我可以换出数据库层进行测试,并使用模拟测试。
系统管理员应该控制生产配置文件,因为理想情况下,开发人员不应将任何内容推送到生产中。
Spring 对 DI 有一个很好的设置,尽管它并不轻量。
我发现 Unity 框架学习起来并不简单,但是一旦您使用它,添加新的注入类就变得非常容易。
因此,一开始,任何新的东西都可能会让人害怕,但当您熟悉这个概念时,您就会看到优点,例如我解释的三个配置文件。
Depending on the language you use there are some DI frameworks that aren't as scary, though you will have some config files, but they shouldn't be scary, but useful.
For example, I have one config file for development, one for testing and one for production.
So, depending on the one I use, the database connections can be changed, and I can swap out the database layer for tests, and use mock tests.
The sysadmins should control the production config files, as the developers shouldn't push anything to production, ideally.
Spring has a nice setup for DI, though it isn't lightweight.
I have found that the Unity Framework isn't trivial to learn, but once you are using it it is pretty easy to add new classes for injection.
So, anything new may be scary, initially, but as you get comfortable with the concept you can see advantages, such as I explained about the three config files.
我的情况可能与您的情况不同,因为我们已经拥有一个专为非常灵活的配置而设计的系统,因此向该配置添加依赖项注入几乎是微不足道的,但在我看来,使用服务定位器模式不会为您节省太多配置,因为您必须这样做仍然指定如何定位服务。能够灵活地注入模拟对象进行测试对于使用依赖注入来说几乎是无价的好处,所以我想说配置开销可能只是您需要接受才能获得好处的业务成本。
My situation may be different than yours in that we already have a system designed for very flexible configuration so adding dependency injection to that configuration was almost trivial, but it seems to me that using the service locator pattern will not save you much configuration as you must still specify how to locate the services. Being able to flexibly inject mock objects for testing is an almost invaluable benefit to using dependency injection, so I would say that configuration overhead may just be a cost of doing business you need to accept to gain the benefits.