我对此进行了大量搜索,但没有找到有凝聚力的东西。 我是一个相对较新的开发人员,刚刚开始我的第一个专业开发职位。 我知道即使在基础知识领域我也有很多东西需要学习。 基于听播客、阅读博客、论文等; 我逐渐认识到,在设计和构建软件时牢记关注点分离、IOC、依赖注入似乎是正确的做法。 我获得了非常高水平的概念,并希望尽可能地利用它来完成我所做的事情。
所以,这就是问题所在。 我到底怎么才能这样设计东西呢? 我所在的团队继承了一个基于网络的产品,该产品耦合非常紧密,文档非常少,而且通常不是一个易于维护的软件。 每个人似乎都喜欢移除这对夫妇中的一些人的想法。 他们喜欢开发自动化测试的想法(根据我的阅读,使用松散耦合的组件更容易做到这一点)。 似乎没有人知道该怎么做。 我愿意尝试一下,但我需要指导。 我发现的所有内容似乎总是以非常高层次的方式谈论这些东西,或者相反,只关注整体的一小部分。 我想要一些有关书籍、教程系列、视频或其他内容的指导,这些内容采用一些现实世界的示例并向您展示如何应用这些原则。 理想情况下,我希望看到这样的内容......“以这个订单输入应用程序为例。这就是今天大多数人使用标准 ADO.NET 数据集将其组合在一起的方式,等等......等等......等等。现在!如果我们应用 IOC 原则来使其成为一个松散耦合的项目,那么您可以采取不同的做法,这就是您这样做的原因,以及当您尝试实现此目标时必须考虑的事项。”
我知道这有点啰嗦,我只是有点沮丧,因为我发现的大多数综合培训材料根本没有以初学者可以从一开始就应用良好实践的方式讨论这个主题一。
感谢大家抽出时间。
史蒂夫
I've done quite a bit of searching on this and haven't had much luck finding something cohesive. I'm a relatively new developer and have just started in my first professional development position. I know that I have a great deal to learn even in the realm of the basics. Based on listening to PodCasts, reading blogs, papers etc; I've come to understand that keeping separation of concerns, IOC, Dependency Injection in mind when designing and building software seems to be the right thing to do. I get the concepts at a VERY high level and want to approach what I do with this in mined as much as I can.
So, here's the rub. HOW the heck do I design stuff this way? I work on a team that has inherited a web based product that is very tightly coupled, very poorly documented and generally not an easy to maintain bit of sofware. Evryone seems to like the idea of removing some of this couple. They like the idea of developing automated tests (which from what I've read is easier to do with loosely coupled components). Nobody seems to know how to do it. I'm willing to take a stab at it, but I need guidance. Everything I've found always seems to talk about this stuff in a very high level way, or conversely, focuses on just a small piece of the whole. I'd like some guidance on a book, or series of tutorials, or videos, or SOMETHING that takes a somewhat real-world example and shows you how to apply these principles. Ideally, I'd LOVE to see something that says..."Take this order entry app, for example. THIS is how most people put it together today using standard ADO.NET DataSets, blah...blah...blah. NOW! If we apply the IOC principles to make this a loosely coupled project, here's what you do differently. Here's WHY you do it this way, and here's what you have to consider when you try to accomplish this."
I know this is a bit long winded, I'm just a bit frustrated that most of the comprehensive trainig material out there that I've found simply doesn't discuss this topic in a way that someone starting out can apply good practices from day one.
Thanks all for your time.
Steve
发布评论
评论(6)
我也遇到同样的情况,我买了这两本书
(PDF版本打印)
http://www.manning.com/osherove/
和
http://www.manning.com/prasanna/
I was in the same situation and i bought these two books
(The PDF version to print out)
http://www.manning.com/osherove/
and
http://www.manning.com/prasanna/
您绝对应该在 dimecasts.net 上查看 IoC 截屏视频。 它们非常简单,将帮助您掌握一些概念。
You should definitely check out the IoC screencasts on dimecasts.net. They are very straight-forward and will help you to grasp some of the concepts.
我建议您查看这篇博文中提到的 James Kovacs 的书。 其中一个对你的处境尤其令人心酸。 这就是“有效地处理遗留代码”。 它对重构的概念有很好的解释。 它还提供了这些概念的示例,尽管是在 C#、Java 和 C++ 中,但很容易理解。
I would suggest that you check out the book James Kovacs mentioned in this blog post. One is particularly poignant for your situation. That is "Working Effectively with Legacy Code." It has very good explanations of the concepts of refactoring. It also gives examples of these concept that, although in a C#, Java, and C++, are very easy to follow.
我只能描述我们的想法。 我们从各种在线图书馆借用了可用性语法等,但代码都是我们的。
基本上,我们拥有所谓的 ServiceContainer,一个对象。 它总是有一个全局实例,如果您愿意,可以是静态的单例副本,因此在 Web 应用程序中,在应用程序域中的所有用户之间共享。
ServiceContainer 包含规则。 这些规则规定了诸如如果有人请求 XYZ 类型的对象,您可以按照以下方式向他们提供该对象。
例如,规则可能是为了让某些代码获取实现 IDbConnection 的对象,容器将构造、配置并返回一个新的 SqlConnection 对象。
因此,相关代码不知道也不关心它正在使用 SqlConnection 对象,而不是 OleDbConnection 对象。
写完后,我意识到这不是一个很好的例子,因为最终您最终会向连接请求命令对象,并且您为该对象提供的 SQL 语法必须根据连接类型进行定制。 但如果我们现在可以忽略这一点,代码将不知道它正在连接到 SQL Server,它只知道它有一个连接对象。
现在,需要为这里讨论的代码提供它应该使用的容器,以及规则。 这意味着从单元测试的角度来看,我可以创建 ServiceContainer 的新实例,向其中写入新规则以用于测试目的,并要求代码执行其操作。 最终,代码想要执行一些 SQl(在本例中),而不是与真实的数据库通信,而是调用 IDbConnection 和 IDbCommand 的测试实现,从而给我一个机会来验证事情是否正常工作。
更重要的是,它为我提供了一种返回适合测试的已知虚拟数据的方法,而无需模拟整个数据库。
现在,对于注入部分,在我们的例子中,我们可以要求容器为我们提供必须构造的、依赖于其他对象的对象。
例如,假设我们有一个 IDataAccessLayer 接口和一个 MSSQLDataAccessLayer 实现。
虽然该接口没有给我们任何外部迹象表明它执行任何日志记录,但这里的实际实现需要有某个地方来记录它执行的所有 SQL。 因此,该类的构造函数可能如下所示:
在 ServiceContainer 对象中,我们注册了以下规则(这是我们的语法,您不会在其他任何地方找到它,但它应该很容易遵循):
FactoryScoped 意味着每次我向容器询问一个对象时,我都会得到一个新的。
如果我用英语编写规则,则规则如下:
请注意,我之前说过 MSSQLDataAccessLayer 的构造函数采用 ILogger,但我在这里没有指定任何参数? 这为我提供了以下代码来获取访问层对象:
现在发生的情况是,容器对象发现该对象是 MSSQLDataAccessLayer,并且它有一个构造函数。 此构造函数需要一个 ILogger 对象,但你瞧,容器知道如何创建一个。 因此,容器将构造一个新的 FileLogger 对象,并将其默默地传递给 MSSQLDataAccessLayer 对象的构造函数。
因此,许多应用程序依赖项的配置可以一次性完成,在某个中心位置并在启动期间执行,而其余代码则完全不知道这里发生的所有魔力。
出于单元测试的目的,我可以重写规则以提供我自己的虚拟记录器对象,该对象仅将记录的文本存储在内存中,这使我可以轻松验证我期望的代码记录的内容是否实际记录,而无需读取之后归档。
这些规则为我们提供了如何实际提供对象实例的强大功能:
我们查看了 autofac 在提出我们自己的之前,基本上我们只是查看了显示调用语法示例的 wiki,然后坐下来编写我们自己的系统可以满足我们的需要。
I can only describe what we have come up with. We've borrowed usability syntax and such from various online libraries, but the code is all ours.
Basically, we have what we call a ServiceContainer, an object. There is always a global instance of it, a singleton copy if you wish, static, and thus in a web-application, shared between all users in the appdomain.
A ServiceContainer contains rules. The rules says things like If someone asks for an object of type XYZ, here's how you go about providing them with it.
For instance, a rule might be that in order for some code to get an object that implements IDbConnection, the container would construct, configure, and return a new SqlConnection object.
The code in question would thus not know, and not care, that it is using a SqlConnection object, as opposed to a OleDbConnection object.
Having written that, I realize this is not a very good example, because ultimately you end up asking the connection for command objects, and the SQL syntax you give to that object must be tailored to the type of connection. But if we can disregard that point right now, the code would not know that it is connecting to SQL Server, it just knows that it has a connection object.
Now, the code in question here would need to be given the container it should use, and thus the rules. This means that from a unit-testing perspective, I could create a new instance of ServiceContainer, write new rules into it for testing purposes, and ask the code to do its thing. Ultimately the code would want to execute some SQl (in this instance) and instead of talking to a real database, it would call my test implementation of IDbConnection and IDbCommand, and thus give me an opportunity to verify that things are working.
More importantly, it gives me a way to return back known dummy-data fitting the test, without having to mock up an entire database.
Now, for the injection part, in our case we can ask the container to provide us with objects, that has to be constructed, that relies on other objects.
For instance, let's say we have a IDataAccessLayer interface, and a MSSQLDataAccessLayer implementation.
While the interface doesn't give us any outwards sign that it does any logging, the actual implementation here needs to have somewhere to log all the SQL it executes. Thus, the constructor for the class might look like this:
In the ServiceContainer object, we have registered the following rules (this is our syntax, you won't find that anywhere else, but it should be easy enough to follow):
FactoryScoped means that each time I ask the container for an object, I get a new one.
The rules, if I write them in english, are like this:
Notice that I said before that the constructor to MSSQLDataAccessLayer takes an ILogger, yet I didn't specify any parameters here? This gives me the following code to get hold of the access layer object:
What happens now is that the container object figures out that there the object is MSSQLDataAccessLayer, and that it has a constructor. This constructor requires an ILogger object, but lo and behold, the container knows how to make one. The container will thus construct a new FileLogger object, and pass this to the constructor of MSSQLDataAccessLayer object, silently.
Configuration of much of the application dependencies can thus be done once, somewhere central and executed during startup, while the rest of the code is blissfully unaware of all the magic happening here.
For unit-testing purposes I can rewrite the rules to provide my own dummy logger object that just stores the logged text in memory, which allows me to easily verify that what I expected the code to log was actually logged, without having to read in a file afterwards.
The rules gives us lots of power on how to actually provide object instances:
We looked at autofac before coming up with our own, basically we just looked at the wiki showing examples of call syntax and then sat down and wrote our own system that did what we needed.
我必须引导您访问我为一个询问良好单元测试示例的人回答的同一个开源项目。
I have to direct you to the same open source project I answered for a person asking for example of good unit testing.
本文作者:Ayende 是我见过的最好的 IoC 介绍。
This article by Ayende is best introduction to IoC I have ever seen.