6

我已经对此进行了很多搜索,并且没有太多运气找到有凝聚力的东西。我是一个相对较新的开发人员,刚刚开始我的第一个专业开发职位。我知道即使在基础领域我也有很多东西要学。基于收听 PodCast、阅读博客、论文等;我开始明白,在设计和构建软件时考虑分离关注点、IOC、依赖注入似乎是正确的做法。我在非常高的水平上获得了这些概念,并希望尽可能多地接近我对此所做的事情。

所以,这就是问题所在。我怎么会这样设计东西?我在一个团队工作,该团队继承了一个基于 Web 的产品,该产品耦合非常紧密,文档记录非常差,而且通常不容易维护一些软件。Evryone 似乎喜欢移除这对夫妇中的一些人的想法。他们喜欢开发自动化测试的想法(根据我所读到的内容,使用松散耦合的组件更容易做到这一点)。似乎没有人知道该怎么做。我愿意尝试一下,但我需要指导。我发现的一切似乎总是以一种非常高级的方式谈论这些东西,或者相反,只关注整体的一小部分。我想要一些关于一本书、一系列教程、视频或一些东西的指导,这些东西需要一个真实的例子,向你展示如何应用这些原则。理想情况下,

我知道这有点啰嗦,我只是有点沮丧,因为我发现的大多数综合培训材料根本没有以一种开始的人可以从一天开始应用良好实践的方式讨论这个话题一。

谢谢大家的时间。

史蒂夫

4

6 回答 6

4

您绝对应该查看dimecasts.net上的 IoC 截屏视频。它们非常直截了当,可以帮助您掌握一些概念。

于 2008-11-19T16:49:42.920 回答
4

我也遇到了同样的情况,我买了这两本书

(要打印的 PDF 版本) http://www.manning.com/osherove/http://www.manning.com/prasanna/

于 2008-11-25T05:31:10.430 回答
3

我建议您查看这篇博文中提到的 James Kovacs 书。一个对你的情况特别尖锐。那就是“有效地使用遗留代码”。它对重构的概念有很好的解释。它还提供了这些概念的示例,尽管这些概念在 C#、Java 和 C++ 中很容易理解。

于 2008-11-23T16:02:50.390 回答
2

我只能描述我们想出的东西。我们从各种在线库中借用了可用性语法等,但代码都是我们的。

基本上,我们有我们所说的 ServiceContainer,一个对象。它总是有一个全局实例,如果你愿意,可以是一个单例副本,静态的,因此在 web 应用程序中,在 appdomain 中的所有用户之间共享。

ServiceContainer 包含规则。规则是这样说的:如果有人要一个 XYZ 类型的对象,这就是你如何为他们提供它的方法

例如,一个规则可能是为了让某些代码获得一个实现 IDbConnection 的对象,容器将构造、配置并返回一个新的 SqlConnection 对象。

因此,有问题的代码不知道也不关心它使用的是 SqlConnection 对象,而不是 OleDbConnection 对象。

写完之后,我意识到这不是一个很好的例子,因为最终您会向连接请求命令对象,并且您为该对象提供的 SQL 语法必须根据连接类型进行调整。但是如果我们现在可以忽略这一点,代码就不会知道它正在连接到 SQL Server,它只知道它有一个连接对象。

现在,这里有问题的代码需要给出它应该使用的容器,因此需要给出规则。这意味着从单元测试的角度来看,我可以创建一个新的 ServiceContainer 实例,将新规则写入其中以进行测试,并要求代码执行它的操作。最终,代码会想要执行一些 SQl(在这种情况下),而不是与真正的数据库对话,它会调用我的 IDbConnection 和 IDbCommand 的测试实现,从而让我有机会验证事情是否正常。

更重要的是,它为我提供了一种返回适合测试的已知虚拟数据的方法,而无需模拟整个数据库。

现在,对于注入部分,在我们的例子中,我们可以要求容器为我们提供必须构建的对象,这些对象依赖于其他对象。

例如,假设我们有一个 IDataAccessLayer 接口和一个 MSSQLDataAccessLayer 实现。

虽然接口没有给我们任何外部迹象表明它进行了任何日志记录,但这里的实际实现需要有一个地方来记录它执行的所有 SQL。因此,该类的构造函数可能如下所示:

public MSSQLDataAccessLayer(ILogger logger) { ... }

在 ServiceContainer 对象中,我们注册了以下规则(这是我们的语法,在其他任何地方都找不到,但应该很容易遵循):

ServiceContainer.Global.RegisterFactory<ILogger, FileLogger>()
    .FactoryScoped()
    .WithParameters(
        new Parameter("directory", @"C:\Temp")
    );
ServiceContainer.Global.RegisterFactory<IDataAccessLayer, MSSQLDataAccessLayer>()
    .FactoryScoped();

FactoryScoped 意味着每次我向容器请求一个对象时,我都会得到一个新对象。

规则,如果我用英文写,是这样的:

  • 如果有人需要 ILogger 的实现,请构造一个新的 FileLogger 对象,并获取需要“目录”参数的构造函数,并在传入“C:\Temp”作为参数时使用该构造函数
  • 如果有人需要 IDataAccessLayer 的实现,请构造一个新的 MSSQLDataAccessLayer

请注意,我之前说过 MSSQLDataAccessLayer 的构造函数采用 ILogger,但我没有在这里指定任何参数?这给了我以下代码来获取访问层对象:

IDataAccessLayer dal = ServiceContainer.Global.Resolve<IDataAccessLayer>();

现在发生的情况是容器对象发现该对象是 MSSQLDataAccessLayer,并且它有一个构造函数。这个构造函数需要一个 ILogger 对象,但是你瞧,容器知道如何创建一个。容器将因此构造一个新的 FileLogger 对象,并将其传递给 MSSQLDataAccessLayer 对象的构造函数,静默。

因此,大部分应用程序依赖项的配置可以一次完成,在某个中央位置并在启动期间执行,而其余代码则完全没有意识到这里发生的所有魔法。

出于单元测试的目的,我可以重写规则以提供我自己的虚拟记录器对象,该对象仅将记录的文本存储在内存中,这使我能够轻松验证我期望记录的代码是否实际记录,而无需读取之后归档。

这些规则为我们提供了如何实际提供对象实例的强大功能:

  • 来自委托/方法,这意味着如果我们愿意,我们可以自己完成构建依赖对象的所有魔法
  • 从构造函数中自动生成(或者自动确定要使用哪一个,或者我们可以通过名称/类型提供足够的虚拟参数来选择一个)
  • 或者我们可以为容器提供一个现有实例(这将有点像单例)

在提出我们自己的方法之前,我们查看了autofac,基本上我们只是查看了显示调用语法示例的 wiki,然后坐下来编写了我们自己的系统来满足我们的需要。

于 2008-11-19T16:33:52.653 回答
2

我必须将您引导到我为一个询问良好单元测试示例的人回答的同一个开源项目。

寻找具有大量单元测试的 *small*、开源、c# 项目

我建议看一下 CarTrackr,它具有开发人员应该熟悉的各种 .Net 技术(尤其是 Unity、MVC 框架),并且具有广泛的单元测试。该项目足够简单,可以一口气消化,但又足够复杂,实际上不仅仅是概念验证。他们的 codeplex 网址位于 http://www.codeplex.com/CarTrackr

于 2008-11-19T19:49:38.407 回答
1

Ayende的这篇文章是我见过的对 IoC 的最佳介绍。

于 2009-01-13T16:12:22.103 回答