模式和实践
您可以依赖 Patterns and Practices (模式和实践)
Alex Homer
内容
模式和实践
指导的 Hand
使用抽象 coping
在 Microsoft 的依赖关系的 Brief 的历史记录
扩展自己
摘要
编写计算机代码来是非常困难。当我开始编程家庭计算机更多年前比我关心记住,唯一的方法可以使在超过 desultory 爬网已写入使用计算机的代码运行一个程序。甚至一个简单的文字处理实用程序可能需要几周创建您地计划为变量,内存分配、 编写例程执行简单任务,如屏幕和解码的键盘上的图形字符输入,然后键入一个程序集的每个单独的处理器指令。
目前,通过比较,创建功能强大的代码非常简单。我们获得授予大量工具、 高级语言、 运行时框架、 代码库和能够快速高效构建应用程序的操作系统服务。但是,创建时代码已成为更容易,创建应用程序的任务有不。我们更希望比以往我们现代应用程序中。它们必须通过网络,通信与其他应用程序和服务进行交互、 提供高度交互和响应的用户界面,以及支持丰富的媒体和图形。并且它们必须在当然,是功能强大、 安全、 可靠,易。
实际上,将几乎无法满足要求我们现代应用程序,而不包括持续增长和发展的编程语言、 操作系统、 平台服务和框架。这些应用程序的复杂程度极大增加也已强制我们发现简化和组织代码的方法。年,许多尝试和测试的编程和设计技术已改进,如组件化,对象方向和) 更近服务方向。
模式和实践
工具和框架中的改进使它易于更快地编写代码和现代语言和编程样式,使其更易于编写更好的代码时, 我们过去的 10 到 15 年中创建应用程序的能力了大多数的影响的一个区域已演变和增加接受软件设计模式。
设计模式描述重复发生在应用程序设计和开发,并提供用于处理这些问题的技术的常见问题。模式还描述了当前的行业做法,用于解决体系结构问题,并用于处理设计复杂性要求的应用程序。代码和解决方案的元素的排列方式是软件设计的核心今天,并模式提供我们简化和组织这些元素的方法,从而提供最佳的机会以最大化性能、 灵活性和可维护性的应用程序。
4,Erich 伽玛、 Richard Helm、 Ralph Johnson 和 John M 的 Gang 的基本新簿发布以来Vlissides,设计模式: 可重用的面向对象的软件 (Addison-Wesley,1996),记录许多我们会立即授予的基本设计模式的元素,可供开发人员和设计器的设计模式的增长速度显著。几乎所有方面的软件创建具有相都关联的设计和实现的模式和只记录所有已经成为一个不可能的任务。相反,设计人员和开发人员倾向于到 specialties 分段,并了解最适用的专业技术自己区域模式。
指导的 Hand
在 2002,Microsoft Corporation 模式和实践组发布应用程序体系结构为.NET: 设计应用程序和服务指南,一起使基本设计指导和专家建议以帮助 Microsoft.NET Framework 上构建应用程序的架构师。但是,技术更改随时间,和而设计和开发指南中描述的基础知识是同样今天,原始指南没有不涉及的一些.NET Framework 的新功能或有效解决设计问题引发的应用程序的新类型。
最近的几个月广泛的行业专家和行业专家,内部和外部的 Microsoft,团队已经创建了新版本对 Microsoft.NET Framework 提供要构建的全面介绍和设计解决方案指南的协作。Microsoft 应用程序体系结构指南 (第二版) 介绍高级体系结构原则模式及当前认为在可接受的设计和开发实践。它还包含有关这些因素对特定类型的应用程序,指南并提供了许多平台服务和代码库可以轻松实现了广泛概述。
当然,到借用常用短语,软件和系统体系结构是这 embraces 寿命、 在的世界和所有的问题。没有一个出版物可以回答每个可能的问题或希望提供完全全面覆盖每个可能的情况。但是,新的指南旨在提供您需要是否只启动出 designing.NET 基于 Framework 的应用程序,从另一个平台,查找特定信息和建议,完成架构师转向.NET Framework 的经验丰富的设计器,或只是兴趣了解信息广泛的方案和由.NET Framework 提供的商机的信息。
使用抽象 coping
为了说明行业做法,指南列出了设计几乎任何类型的应用程序时应该应用的一般原则。这些原则包括维护分离使用抽象实现层和组件,实现服务位置的功能和管理 crosscutting 问题 (如日志记录和安全性之间的松散耦合的问题。虽然这些可能似乎是需要但不相关的目标一种方法可以帮助您轻松地应用多个设计原则。依赖项反转原则意味着通过抽象,而不是具体实现的问题的分离。在设计模式方面可以通过应用控件 (IoC) 模式的反转和其相关的图案依赖性注入 (DI) 实现此。
在理论上就很简单。而不是每个类或组件将用来执行某些活动或进程实际具体类型指定在设计时,您可以从以前配置类型的容器中检索相应的对象的排列这些类或组件映射并注册类型。是例如 图 1 中简单应用程序中所示,数据访问组件需要日志记录组件服务。因为您已正确提取代码特定于任务的和特定于应用程序的代码在 crosscutting 代码,您可能要选择多个日志记录组件。可能是一个设计用于当 Debugging,另一个用于使用自己的网络上的内部运行该应用程序的 Application 和第三个最适合的利用监视环境 (如 Microsoft System Center) 的一个企业级系统中运行。
图 1 这样的分层和日志记录组件在不同使用一个简单应用程序
甚至可能具有多个数据访问组件,每个设计用于特定环境中或使用不同类型的数据存储区。因此,您的业务层需要选择适当的数据层组件,根据当前的部署或运行时环境。在类似的方式,您可能必须应用程序使用重复,如电子邮件发送服务或数据转换服务的服务。依赖性注入可作为一个服务位置功能来帮助在运行时检索实例 (一个新实例或现有实例) 服务的应用程序。
这些示例的每个有效地另一个,描述应用程序的一个部件的依赖项,并解决这些依赖项不会不紧密结合对象的方式是依赖项反转原则的目的。
在 Microsoft 的依赖关系的 Brief 的历史记录
尽管原则的依赖项取反值已很长时间周围,可帮助开发人员在 Microsoft 平台上运行的应用程序中实现它的功能是相对较新的。实际上,没有 renowned 开发人员访问在 Microsoft 校园时在 Java 世界中的 remarked 常规 belief 已在 Microsoft 的人可能拼写"依赖性注入"的一篇文章 而这就是无须肯定,一个城市的 myth 情况是工具来帮助开发人员实现许多常见的模式没有被公司的大部分区域中的一个优先级。
但是,Microsoft 模式和实施方案小组通过我们的内部公司,但主要产品开发团队和部门之外的唯一位置表示出。p & p,"证明可预测的结果的做法"我们标志行所示,目标是开发人员提供指南、 工具、 库、 框架和其他功能以帮助他们设计并构建 Microsoft 平台上的更好地应用程序的多种。在快速快速我们MSDN 上的主页将说明我们提供的资产的广泛。
这些资产之间是多个产品的使用的相关性注入模式中包括企业库、 复合应用程序框架和软件工厂。这些资产的开发,过程中特别原始的复合应用程序块 (CAB),它成为清除可重用和高度可配置的相关性注入机制已要求),所以团队生成对象生成器的原始版本。
对象生成器是几乎完全可配置的并现在用于各种产品 p & p 整个和其他 Microsoft 内部。但是,很很难使用。它需要一个很好的多个参数,执行复杂的对象的并且公开一组应用所需的配置必须处理的事件。初始尝试为 CAB 项目的一部分立即显示这将一个 uphill 任务文档对象生成器。此外,对象生成器是而超过一个相关性注入容器,并且它似乎是多余的常见要求实现 DI 和 IoC 模式。
Enterprise Library 4.0 开发,过程中的对象更新生成器不简化它,而使其更加快速和高效。它还被 fine-tuned 用于第一个主要的相关性注入机制,旨在 squarely 开发人员需要实现 DI 和 IoC 模式的 Microsoft。对象生成器是在基础 Unity,支持构造函数注入、 属性注入和方法调用注入的轻量、 可扩展的相关性注入容器。
一致提供特别是会将其为层次结构对象的结构和依赖项的简化的对象创建的功能的要求的抽象在运行时或通过配置; crosscutting 问题 ; 简化的管理,并增加灵活性推迟到容器的组件配置。它是服务位置功能,并且允许客户端存储或缓存容器甚至在 ASP.NET Web 应用程序。
早期的 2008 中第一个版本 Unity 发布,以来它已作为默认机制用于实现依赖项反转许多 p 和 p 资产中找到家庭。一致已也继续发展时剩余的向后兼容 ; 您可以使用它启用 Enterprise Library 中的功能,以及将其作为独立的 DI 容器。在最新的版本中,它提供允许方面面向编程技术 (如策略注入的实现的功能,实现实例,并键入拦截 (通过插件的扩展名)。
一致也已生成针对特定任务其他 DI 容器实现要求,如非常轻型实现用于中并使用移动设备和智能电话。同时,Unity 和企业库 arena 中计划的未来发展包括打开其他第三方容器机制的 Enterprise Library 提供的 Unity 启用新的功能的其他扩展的功能。应用依赖关系反转
保留此历史记录的干扰,以及返回到假想应用程序,如何可以应用依赖项反转原则来实现该目标,讨论前面,问题、 抽象和松散耦合的分离的?答案是一个依赖项注入容器如不是 Unity,配置相应的类型,键入映射,然后允许应用程序检索并在运行时插入正确的对象的实例。图 2 说明了如何使用 Unity 应用程序块来实现此容器。在这种情况下您填充该容器之间数据组件和日志记录的组件的接口定义特定的具体实现这些接口所需应用程序使用的类型映射。
图 2 相关性注入可以选择相应的组件在运行时根据配置容器 。
运行时业务层将查询容器以检索正确的数据图层组件的根据其当前映射的一个实例。数据层然后将查询容器以获取适当的日志记录组件的具体取决于为该接口类型存储在映射的实例。这些基类型之间继承的具体类型可以映射为一种替代方法、 数据和日志记录组件可能会继承相应基类和容器中的注册。
此容器驱动方法解决类型和实例意味着开发人员是随意更改数据和日志记录的组件实现,只要这些实现提供所需的功能并提供适当的接口 (是例如通过实现映射的接口,或从映射的基类继承)。在使用容器的注册类型、 类型映射或对象的现有实例的方法的运行时,可能在代码中设置容器配置。或者,可以通过从配置源或文件,如 Web.config 或 app.config 文件中加载登记来填充该容器。
如果要注册类型的多个实例,您可以定义每个和然后解决通过指定名称的不同类型名称。注册,可以指定易于通过注册服务对象作为单一实例或特定生存期 (如) 每个线程获得服务位置样式功能在该对象的生存期。以下代码示例演示该类型映射注册与容器的一些示例:
C#
// Register a mapping for the CustomerService class to the IMyService interface.
myContainer.RegisterType<IMyService, CustomerService>();
// Register the same mapping using a mapping name.
myContainer.RegisterType<IMyService, CustomerService>("Data");
// Register the first mapping, but as a singleton.
myContainer.RegisterType<IMyService, CustomerService>(
new ContainerControlledLifetimeManager());
注意: 代码示例引用类和类型使用只是类名称。 您可以在配置文件为别名完全限定的类型名称的类,它使用配置文件时,可简化容器注册中使用类型别名定义。
若要检索对象的实例,您只是查询容器指定类型、 接口类型或基类类型 (以及该的名称),如果注册使用名称的类型下一个示例中所示。 如果已注册并创建或返回相应的对象的一个实例,该容器解决该的类型。 如果它未注册容器只是创建该类型的新实例并将其返回。 为什么将您解决项通过容器没有注册为该类型时? 其目的是利用 Unity 和许多其他 DI 容器机制,提供了在其他和非常有用功能,能够插入用构造函数、 属性 setter 和方法调用插入对象。
C#
// Retrieve an instance of the mapped IMyService concrete class.
IMyService result = myContainer.Resolve<IMyService>();
// Retrieve an instance by specifying the mapping name.
IMyService result = myContainer.Resolve<IMyService>("Data");
是例如创建通过容器对象的一个实例时, Unity 将检查该构造函数,并将自动注入适当类型的实例构造函数参数。 回到我们前面的简单的应用程序示例,数据访问组件可能具有对作为参数的日志组件引用的构造函数。 如果此参数类型是接口或基类记录与容器注册的组件,Unity 将解析映射的类型、 创建实例,并将它传递给数据组件 (如 图 3 中所示) 的构造函数。 您不执行任何操作除了注册映射。
图 3 注入构造函数参数的对象
C#
// In main or startup code:
// Register a mapping for a logging component to the ILogger interface.
// Alternatively, you can specify this mapping in a configuration file.
myContainer.RegisterType<ILogger, MyLogger>();
...
// In data access component:
// Variable to hold reference to logger.
private ILogger _logger = null;
// Class constructor. Unity will populate the ILogger type parameter.
public DataAccessRoutines(ILogger myLogger)
{
// store reference to logger
_logger = myLogger;
_logger.WriteToLog("Instantiated DataAccessRoutines component");
}
这意味着您可以更改实际应用程序使用只需通过更改容器的配置的具体类型,或者在设计时,在时间通过编辑该的配置上运行或动态基于您的代码从环境中收集,并使用以创建或更新容器中的映射某个值。 您可以插入调试日志记录组件需要时, 或插入新"超级快速"日志记录组件找到旧是否太慢。 同时,系统管理员可以更新配置,根据需要监视、 管理,以及在满足不断变化的环境和操作的问题的运行时调整应用程序行为。
同样,如果两个对象之间的依赖项 (如) 在其演示者视图的依赖项实现在模型-视图-演示者 (<b > MVP </ b >) 模式时您可用于依赖性注入放宽这些类之间耦合。 只需为演示者类型定义视图类的属性或基于类类型并标记属性的一个依赖项属性,为下一个示例中所示:
C#
// Variable to hold reference to controller.
private IPresenter _presenter;
// Property that exposes the presenter in the view class. Unity will inject
// this automatically because it carries the Dependency attribute.
[Dependency]
public IPresenter MyViewPresenter
{
get { return _presenter; }
set { _presenter = value; }
}
注意: 属性是最快捷的方法指定要插入属性。如果要使用属性来避免离合器到容器的类) 可以而是使用配置文件或 Unity API 若要指定应将插入的属性。
通过容器中解决它创建视图时 Unity 将检测该依赖项属性,自动解决在适当的具体演示者类的实例并将其设置为视图类的该属性的值。Unity 所附带的快速入门示例演示 Windows 窗体应用程序中的此方法。实际解决通过,从而导致 Unity 来创建并填充整个应用程序使用构造函数和属性 setter 注入的几个依赖项的容器应用程序的主窗体。
扩展自己
一致提供大量 DI 相关的功能但没有始终额外您想要获得的内容。以使其通用时被扩展,以便您可以适应其自己的特定要求满足的要求,最大数量的 Unity 挑战。此功能通过允许您执行几乎任何方面的管理对象创建和检索的容器扩展来实现。
例如,附带 Unity 快速启动演示实现简单属性驱动 Publish\Subscribe 机制的一个容器扩展名。作为 Unity 创建的对象实例,它 wires 了事件处理程序为其基于类文件中的属性。创建或检索每个类型通过该容器可帮助您调试复杂的应用程序时,另一个示例将生成详细日志记录信息。
因为 Unity 允许您以交互基础对象生成器机制,通过将容器扩展,有关将提供这种大的灵活性。啊,您可能会说,但对象生成器非常难以使用和不完整地说明。事实上,Unity 文档不会包含有关方面的方式您从与之交互一个容器扩展的对象生成器的信息,并快速入门示例提供大量的示例代码,您可以使用和修改。
摘要
没有应用程序体系结构和设计上的多个视图。ISO/IEC 标准 42010:2007 / IEEE 1471"推荐的软件需要系统的体系结构描述的操作与"基本组织系统 embodied 其组件,相互和环境和它的设计和演变指导原则及其关系中的"描述软件体系结构。但是,企业应用程序体系结构 (Addison-Wesley,2002) 的他簿模式,Martin Fowler 说的".in 结束,体系结构归结为重要的资料是任何,"这是一更简单方法捕获软件体系结构的精神 !
Microsoft 应用程序体系结构指南 (第二版) 将帮助您了解重要内容是这样,您可以生成更好地,较高质量应用程序更快和更有效地。您已看到本文一特定区域中,利用依赖性注入和取反值的控件的模式,可以帮助您实现的设计目标升级指南的许多。这包括分离问题,抽象实现层、 服务位置和 crosscutting 问题改进管理功能实现之间的松散耦合的使用。
Alex Homer 是与 Microsoft 模式和实施方案小组文档工程师。有关生命周期、 技术和世界上其随机 ravings 通常可查看 https://blogs.msdn.com/alexhomer/.