你将见到部分可用于管理对象在应用程序中怎么着实例化的替代情势,工厂、服务一定和依赖注入

Introduction

Unity文书档案阅读 第一章 重视注入,unity第一章

Introduction

介绍
Chapter 1 outlines how you can address some of the most common
requirements in enterprise applications by adopting a loosely coupled
design to minimize the dependencies between the different parts of your
application. However, if a class does not directly instantiate the other
objects that it needs, some other class or component must take on this
responsibility. In this chapter, you’ll see some alternative patterns
that you can use to manage how objects are instantiated in your
application before focusing specifically on dependency injection as the
mechanism to use in enterprise applications.

第3章概述了哪些通过动用松散耦合设计来最小化应用程序的不等部分之间的重视性关系,从而消除公司应用程序中的1些最广大的须求。可是,假使二个类不直接实例化它须求的其余对象,一些任何类或机件必须承担那么些权利。在本章中,您将见到局地可用于管理对象在应用程序中哪些实例化的替代情势,在你精晓你的集团应用使用的话注入机制以前。

Factories, Service Locators, and Dependency Injection

厂子、服务一定和依靠注入 Factories, service locators, and dependency injection are all
approaches you can take to move the responsibility for instantiating and
managing objects on behalf of other client objects. In this section,
you’ll see how you can use them with the same example you saw in the
previous chapter. You’ll also see the pros and cons of the different
approaches and see why dependency injection can be particularly useful
in enterprise applications.

工厂、服务一定和依靠注入是您能够应用的有着路线,用于转移替代其他客户对象实例化和管理对象的天职。在本节中,您将看到什么样行使上1章中所示的示范。您还将见到分裂措施的利害,并询问怎么注重注入在集团应用程序中特别有用。

Factory Patterns

厂子方式
There are three common factory patterns. The Factory Method and Abstract
Factory patterns from “Design Patterns: Elements of Reusable
Object-Oriented Software” by Gamma, Erich, Richard Helm,Ralph Johnson,
and John Vlissides. Addison Wesley Professional, 1994., and the Simple
Factory pattern.

有二种普遍的工厂情势。工厂方法和浮泛工厂形式来自Gamma, 埃里克h, RichardHelm,拉尔夫 Johnson, and John Vlissides.艾迪生 卫斯理 Professional,
一9九1“设计方式:可选取的面向对象软件的成分”,和不难工厂方式。

The Factory Method Pattern

工厂方法情势
The following code samples show how you could apply the factory method
pattern to the example shown in the previous chapter. The first code
sample shows how you could use a factory method to return an instance of
the TenantStore class to use in the ManagementController class.
In this example, the CreateTenantStore method is the factory method
that creates the TenantStore instance and the Index method uses
this instance as part of its logic.

以下代码示例突显怎么将工厂方法情势应用于上1章中所示的演示。第一段代码示例演示怎样行使工厂方法重回ManagementController
类中利用的TenantStore 类的实例。在那些示例中,CreateTenantStore
方法是3个创建TenantStore
示例的工厂方法,Index形式应用此实例作为其逻辑的一片段。

public class ManagementController : Controller
{
    protected ITenantStore tenantStore;
    public ManagementController()
    {
        this.tenantStore = CreateTenantStore();
    }
    protected virtual ITenantStore CreateTenantStore()
    {
        var storageAccount = AppConfiguration.GetStorageAccount("DataConnectionString");
        var tenantBlobContainer = new EntitiesContainer<Tenant>(storageAccount, "Tenants");
        var logosBlobContainer = new FilesContainer(storageAccount, "Logos", "image/jpeg");
        return new TenantStore(tenantBlobContainer, logosBlobContainer);
    }
    public ActionResult Index()
    {
        var model = new TenantPageViewData<IEnumerable<string>>(this.tenantStore.GetTenantNames())
        {
            Title = "Subscribers"
        };
        return this.View(model);
    }
    ...
}

Using this approach does not remove the dependencies the
Management-Controller has on the TenantStore class, nor the
FilesContainer and Entities-Container classes. However, it is
now possible to replace the underlying storage mechanism without
changing the existing ManagementController class as the following
code sample shows.

运用那种办法不能够去除ManagementControllerTenantStore
类的注重性,也不会删除FilesContainer和EntitiesContainer类。不过,他未来可以替换底层的贮存机制而不用更改现有的ManagementController
类,就像是上边代码所示范的。

public class SQLManagementController : ManagementController
{
    protected override ITenantStore CreateTenantStore()
    {
        var storageAccount = ApplicationConfiguration.GetStorageAccount("DataConnectionString");
        var tenantSQLTable = ...
        var logosSQLTable = ....
        return new SQLTenantStore(tenantSQLTable, logosSQLTable);
    }
    ...
}

The factory method pattern enables you to modify the behavior of a class
without modifying the class itself by using inheritance.

选择持续,工厂方法允许你修改类的行事,而无需修改类本人。

The application can use the SQLManagementController class to use a
SQL-based store without you needing to make any changes to the original
ManagementController class. This approach results in a flexible and
extensible design and implements the open/closed principle described in
the previous chapter. However, it does not result in a maintainable
solution because all the client classes that use the TenantStore
class are still responsible for instantiating TenantStore instances
correctly and consistently.

以此利用能够利用SQLManagementController 类去选取SQLbased
存款和储蓄,未有在原ManagementController
类中做其它修改。那种办法导致灵活和可扩大的统一筹划,并贯彻前壹章中讲述的开/闭原理。但是,它不会生出可保险的消除方案,因为运用TenantStore
类全数的客户类照旧承担任正剧中人物确和千篇一律的实例化TenantStore 实例。

It is also still difficult to test the ManagementController class
because it depends on the TenantStore type, which in turn is tied to
specific storage types (FilesContainer and EntitiesContainer).
One approach to testing would be to create a
MockManagementController type that derives from
Management-Controller and that uses a mock storage implementation to
return test data: in other words you must create two mock types to
manage the testing.

ManagementController 类的测试仍旧是费劲的,因为它借助TenantStore
类型,而那又凭借于特定的储存类型(FilesContainer
EntitiesContainer)。一种测试方法是创建一个源点ManagementControllerMockManagementController项目,并应用模拟存储完结重回测试数据:换句话说,您必须创设八个模拟类型来治本测试。

In this example, there is an additional complication because of the way
that ASP.NET MVC locates controllers and views based on a naming
convention: you must also update the MVC routes to ensure that MVC uses
the new SQLManagementController class.

在这些示例中,还有贰个外加的错综复杂,因为ASP.NET
MVC基于命名约定定位控制器和视图的点子:你不洗还要修改MVC的路由去保证MVC使用新的SQLManagementController
类。

Simple Factory Pattern

总结工厂情势
While the factory method pattern does not remove the dependencies from
the high-level client class, such as the ManagementController class,
on the low-level class, you can achieve this with the simple factory
pattern. In this example, you can see that a new factory class named
TenantStoreFactory is now responsible for creating the
TenantStore instance on behalf of the ManagementController
class.

固然工厂方法形式不能够从最底层类中移除高层客户类(ManagementController
类)的依靠,但能够利用简便的厂子格局实现此指标。在那个示例中,你能够看到名称为TenantStoreFactory
的新工厂类,今后承受代表ManagementController 类创建TenantStore
的实例。

public class ManagementController : Controller
{
    private readonly ITenantStore tenantStore;
    public ManagementController()
    {
        var tenantStoreFactory = new TenantStoreFactory();
        this.tenantStore = tenantStoreFactory.CreateTenantStore();
    }
    public ActionResult Index()
    {
        var model = new TenantPageViewData<IEnumerable<string>>(this.tenantStore.GetTenantNames())
        {
            Title = "Subscribers"
        };
        return this.View(model);
    }
    ...
}

The simple factory pattern removes the direct dependency of the
Management-Controller class on a specific store implementation.
Instead of including the code needed to build a TenantStore instance
directly, the controller class now relies on the TenantStoreFactory
class to create the instance on its behalf.

那一个大约工厂情势移除了ManagementController
对一定存储实现的直接信赖。而不是直接包涵创设TenantStore实例所需的代码,控制器类以往依靠TenantStoreFactory
类来表示其创建实例。

Abstract Factory Pattern

抽象工厂情势
One of the problems that can arise from using the simple factory pattern
in a large application is that it can be difficult to maintain
consistency. For example, the application may include multiple store
classes such as SurveyStore, LogoStore, and ReportStore
classes in addition to the TenantStore class you’ve seen in the
examples so far. You may have a requirement to use a particular type of
storage for all of the stores. Therefore, you could implement a
BlobStoreFactory abstract factory class that can create multiple
blob-based stores, and a SQLStoreFactory abstract factory class that
can create multiple SQL based stores.

在大型应用程序中运用简单工厂形式或然发生的题材之1是或者麻烦维系一致性。例如,除了您在演示中看看的TenantStore类之外,应用程序还能包罗三个商店类,例如SurveyStoreLogoStoreReportStore类。您恐怕要求为具备存款和储蓄使用一定类型的贮存。由此,你能够兑现BlobStoreFactory
抽象工厂类创制多个基于blob的仓库储存,和兑现SQLStoreFactory
抽象工厂类创立四个依照SQL的储存。

The abstract factory pattern is described in “Design Patterns: Elements
of Reusable Object-Oriented Software” by Gamma, et al.

空泛工厂情势在Gamma等人的“设计方式:可复用面向对象软件的法则”中讲述。

The abstract factory pattern is useful if you have a requirement to
create families of related objects in a consistent way.

只要你供给以同样的不二等秘书籍创建连锁对象的族,则抽象工厂格局很有用。

Service Locator Pattern

服务一定方式
Using a service locator provides another variation to this general
approach of using another class to create objects on your behalf. You
can think of a service locator as a registry that you can look up an
instance of an object or service that another class in your application
created and registered with the service locator. The service locator
might support querying for objects by a string key or by interface type.
Often, in contrast to the factory patterns where the factory creates the
object but gives responsibility for managing its lifetime to the client
class, the service locator is responsible for managing the lifetime of
the object and simply returns a reference to the client. Also, factories
are typically responsible for creating instances of specific types or
families of types as in the case of the abstract factory pattern, while
a service locator may be capable of returning a reference to an object
of any type in the application.

行使劳务一定提供了相似方法应用另四个类地替代你创设对象的另贰个变化。你能够认为劳动一定就是注册表,那样你可以寻找对象或服务的实例,应用程序中的另八个类创设并注册到服务定位器。服务一定也能帮助依据字符串的主键或接口类型查询对象。常常,与工厂创建对象,不过客户代码负责管理对象的生命周期的工厂方式相反,服务一定负责管理对象的生命周期,只回去引用到客户端。其余,工厂常常负责创制特定类型或项目标实例的实例,如在抽象工厂情势的景况下,而服务定位器能够能够回来对运用中其余项目标指标的引用。

The section “Object Lifetime” later in this chapter discusses object
lifetimes in more detail.

本节背后的“对象生命周期”部分更详细地探究对象生命周期。

Any classes that retrieve object references or service references from
the service locator will have a dependency on the service locator
itself.
For a description of the service locator pattern, see the section “Using
a Service Locator” in the article “Inversion of Control Containers and
the Dependency Injection pattern” by Martin Fowler.

其余类从服务一定中搜索对象引用或服务使用,都将借助服务一定它自己。

劳务一定方式的贰个描述,请看马丁 Fowler写的小说“Inversion of Control
Containers and the Dependency Injection pattern”中的“Using a ServiceLocator”章节.

For a discussion of why the service locator may be considered an
anti-pattern, see the blog post “Service Locator is an Anti-Pattern” by
Mark Seeman.
For a shared interface for service location that application and
framework developers can reference, see the Common Service Locator
library. The library provides an abstraction over dependency injection
containers and service locators. Using the library allows an application
to indirectly access the capabilities without relying on hard
references.

钻探为何服务定位器只怕被认为是1种反格局,请看MarkSeeman宣布的博客“瑟维斯 Locator is an Anti-Pattern”。

对于应用程序和框架开发人士可以引用的服务一定的共享接口,请参阅Common
瑟维斯Locator库。库提供了对正视注入容器和劳务定位器的悬空。使用库允许应用程序直接待上访问效果而不借助于硬引用。

When using a service locator, every class will have a dependency on your
service locator. This is not the case with dependency injection.

当使用劳务一定,各个类都将凭借你的劳务一定。那不是凭借注入的情况。

Dependency Injection

借助于注入
A common feature of the all the factory patterns and the service locator
pattern, is that it is still the high-level client object’s
responsibility to resolve its own dependencies by requesting the
specific instances of the types that it needs. They each adopt a pull
model of varying degrees of sophistication, assigning various
responsibilities to the factory or service locator. The pull model also
means that the high-level client class has a dependency on the class
that is responsible for creating or locating the object it wants to use.
This also means that the dependencies of the high-level client classes
are hidden inside of those classes rather specified in a single
location, making them harder to test.
Figure 1 shows the dependencies in the simple factory pattern where the
factory instantiates a TenantStore object on behalf of the
ManagementController class.

持有工厂方式和劳务定位器情势的叁个齐声特征是,它依然须求高层客户对象承担通过请求它所要求的特定实体类型来解决它本人的注重性关系。它们各自行使不相同程度的复杂度的拉模型,将分歧的权力和义务分配给工厂或劳务定位器。拉取模型意味着高层客户类有担当创造或稳定它想要使用的目的的借助。那也代表高等客户端类的依赖性隐藏在那个类中,而是在单个地方中钦命,那使得它们更麻烦测试。

图片壹出示简单工厂格局在代表ManagementController
类成立实例化TenantStore 对象的借助关系。

图片1 在工厂情势中的依赖

Dependency injection takes the opposite approach, adopting a push model
in place of the pull model. Inversion of Control is a term that’s often
used to describe this push model and dependency injection is one
specific implementation of the inversion of control technique.
Martin Fowler states: “With service locator the application class asks
for it explicitly by a message to the locator. With injection there is
no explicit request, the service appears in the application class—hence
the inversion of control.” (Inversion of Control Containers and the
Dependency Injection pattern.)
With dependency injection, another class is responsible for injecting
(pushing) the dependencies into the high-level client classes, such as
the Management-Controller class, at runtime. The following code
sample shows what the high-level ManagementController class looks
like if you decide to use dependency injection.

借助于注入采取相反的不二等秘书籍,选拔推模型代替拉模型。控制反转是贰个常用来叙述推模型的术语,信赖注入是控制反转技术的一个切实落到实处。

马丁Fowler写明:“使用服务定位器,应用程序类通过到定位器的新闻显式地伸手它。
使用注入未有明确性的呼吁,服务出现在应用程序类中 –
由此反转控制。”(Inversion of Control Containers and the Dependency
Injection pattern.)

用重视注入,另3个类负责在运转时注入(推送)重视性到高层客户类,如Management-Controller类。以下代码示例显示了1旦您决定使用依赖注入,高级ManagementController类的姿色。

public class ManagementController : Controller
{
    private readonly ITenantStore tenantStore;
    public ManagementController(ITenantStore tenantStore)
    {
        this.tenantStore = tenantStore;
    }
    public ActionResult Index()
    {
        var model = new TenantPageViewData<IEnumerable<string>>(this.tenantStore.GetTenantNames())
        {
            Title = "Subscribers"
        };
    return this.View(model);
    }
    ...
}

As you can see in this sample, the ManagementController constructor
receives an ITenantStore instance as a parameter, injected by some
other class. The only dependency in the ManagementContoller class is
on the interface type. This is better because it doesn’t have any
knowledge of the class or component that is responsible for
instantiating the ITenantStore object.
In Figure 2, the class that is responsible for instantiating the
TenantStore object and inserting it into the
ManagementController class is called the
Dependency-InjectionContainer class.

正如您所见到的这么些示例,ManagementController
构造函数接收二个ITenantStore
实例参数,由此外类注入。ManagementContoller
类仅仅凭借贰个接口类型。那样是更加好地,因为它不需要有担当实例化ITenantStore对象的类或机件的其余文化。

在图纸第22中学,负责实例化TenantStore指标并将其插入到ManagementController类中的类称为DependencyInjectionContainer类。

图表二 当使用重视注入的注重性关系

Chapter 3, “Dependency Injection with Unity,” will describe in more
detail what happens in the DependencyInjectionContainer class

章节三,“用Unity信赖注入”,将尤其详细的讲述DependencyInjectionContainer
类中爆发了如何。

The key difference between the Figure 1 and Figure 2 is the direction of
the dependency from the ManagementController class. In Figure 2, the
only dependency the ManagementController class has is on the
ITenantStore interface.

图片1和图形二的基本点差距在来源ManagementController
类的借助方向上。图形第22中学ManagementController
类仅仅凭借ITenantStore 接口。

Object Composition

对象组成
So far in this chapter, you have seen how dependency injection can
simplify classes such as the ManagementController class and minimize
the number of dependencies between classes in your application. The
previous chapter explained some of the benefits of this approach, such
as maintainability and testability, and showed how this approach relates
to the SOLID principles of object-oriented programming. You will now see
how this might work in practice: in particular, how and where you might
use dependency injection in your own applications.

到本章近年来截止,你曾经观察重视注入怎么样简化类,如ManagementController类,并最小化应用程序中的类之间的重视性关系的数目。前一章解释了部分那种方法的利益,比如可维护性和可测试性,并且出示了该办法如何与SOLID原则的面向对象编制程序相关。你以后能够看来那在具体中如何得以干活的:特别是,在你协调的应用程序中你能够行使信赖注入的不二等秘书籍和地点。

In Figure 2, the DependencyInjectionContainer class may manage the
dependencies of multiple high level client classes such as the
Management-Controller class on multiple service classes such as the
TenantStore class.
You can use either a dependency injection container or implement
dependency injection manually using factories. As you’ll see in the next
chapter, using a container is easier and provides additional
capabilities such as lifetime management, interception, and registration
by convention.

在图形2中,DependencyInjectionContainer
类能够管理高层客户类的七个依靠,例如ManagementController
类上有多个服务类,比如TenantStore 类。

您可以你能够使用依赖注入容器或许应用工厂手工业完毕依靠注入。正如您在下已章节看到的,使用容器是更简单的,并提供附加成效,如生命周期管理、拦截和预定注册。

If you adopt the dependency injection approach, you will have many
classes in your application that require some other class or component
to pass the necessary dependencies into their constructors or methods as
parameters or as property values before you can use them. This implies
that your application requires a class or component that is responsible
for instantiating all the required objects and passing them into the
correct constructors, methods, and properties: your application must
know how to compose its object graph before it can perform any work.
This must happen very early in the application’s lifecycle: for example,
in the Main method of a console application, in the Global.asax
in a web application, in a role’s OnStart method in a Windows Azure
application, or in the initialization code for a test method.

若是您使用依赖注入形式,在您的应用程序中你将有无数类,必要部分其余类或机件将供给的重视性传递到构造函数或艺术作为参数或属性值,然后您才能动用它们。那就觉着那你的应用程序需求2个类或机件是负担实例化全数供给的对象并将它们传递到科学的构造函数,方法和总体性:你的应用程序必须精晓怎么怎样去组成他的靶子图,在能够进行其它工作前。那必须在应用程序的生命周期的中期发生:比如,在控制台程序的Main艺术中,Web应用程序的Global.asax
Windows Azure 应用程序中的剧中人物的OnStart
方法中,或许在测试方法的早先化代码中。

Typically, you should place all the code tells the application how to
build its object graph in a single location; this is known as the
Composition Root pattern. This makes it much easier to maintain and
update the application.

经常,您应该将装有代码告诉应用程序怎样在单个地方营造其目的图;
那被喻为组合根格局。那使得应用程序维护和换代越发简约。

Object Lifetime

目标生命周期
You should determine when to create the objects in your application
based on criteria such as which object is responsible for managing the
state, is the object shared, and how long the object will live for.
Creating an object always takes a finite amount of time that is
determined by the object’s size and complexity, and once you have
created an object, it occupies some of your system’s memory.
在您的应用程序中您应该依据原则(如哪个目的负责管理状态、是还是不是共享对象以及对象足以存活多久)决定曾几何时去创设对象。创设对象总是须求简单的岁月,由对象的大小和错综复杂决定,壹旦创建了对象,它就占用了系统的壹对内存。

In the example, you’ve seen in this chapter, there is a single
Management-Controller client class that uses an implementation of
the ITenantStore interface. In a real application, there may be many
other client classes that all need ITenantStore instances. Depending
on the specific requirements and structure of your application, you
might want each client class to have its own ITenantStore object, or
have all the client classes share the same ITenantStore instance, or
for different groups of client classes each have their own
ITenantStore instance.

在本章的事例中你早已观望,有一个ManagementController客户类使用一个ITenantStore
的实例。在切实可行的应用程序中,那里可能有诸多其余客户类都要求ITenantStore
的实例。依据你应用程序的特殊要求和数据结构,你只怕想要每种客户类都有友好的ITenantStore
对象,或偶有的客户类共享相同的ITenantStore
实例,或每种区别的客户类组有协调的ITenantStore 实例。

If every client object has its own ITenantStore instance, then the
ITenantStore instance can be garbage collected along with the client
object. If multiple client objects share an ITenantStore instance,
then the class or component that instantiates the shared
ITenantStore object must responsible for tidying it up when all the
clients are finished with it.

万1各种客户对象都有和好的ITenantStore
实例,则ITenantStore实例能够与客户端对象一起开始展览垃圾回收。假使多少个客户对象共享三个ITenantStore
实例,则类或机件实例化共享的ITenantStore
对象必须承受在装有客户端达成它后对其开始展览规整。

Whichever way you create an object, there is always a trade-off between
performance and resource utilization when you decide where to
instantiate it.

无论以何种措施创制对象,在控制在何地实例化它时,在性质和能源利用率之间总是存在权衡。

Types of Injection

流入类型
Typically, when you instantiate an object you invoke a class constructor
and pass any values that the object needs as parameters to the
constructor. In the example that you saw earlier in this chapter, the
constructor in the Management-Controller class expects to receive an
object that implements the ITenantStore interface. This is an
example of constructor injection and is the type of injection you will
use most often. There are other types of injection such as property
setter injection and method call injection, but they are less commonly
used.

万般,当你实例化几个对象时,您调用一个类构造函数,并将该目的急需的其它值作为参数字传送递给构造函数。在本章前面包车型地铁例证中您看看,ManagementController
类中的构造函数供给接受实现了ITenantStore
接口的靶子。那是3个构造函数注入的事例,是你最常使用的流入类型。还有任何的局地注入类型,比如属性设置注入和章程调用注入,不过她们1般选拔的可比少。

Property Setter Injection

质量设置注入
As an alternative or in addition to passing a parameter to a
constructor, you may want to set a property value when you instantiate
an object in your application. The following code sample shows part of a
class named AzureTable in an application that uses property
injection to set the value of the ReadWrite-Strategy property when
it instantiates AzureTable object.

作为向构造函数字传送递参数的代表格局或补给措施,您可能必要在应用程序中实例化对象时设置属性值。以下代码示例呈现了应用程序中名称为AzureTable的类的1有的,在实例化AzureTable指标时,它使用性质注入来安装ReadWriteStrategy质量的值。

public class AzureTable<T> : ...
{
    public AzureTable(StorageAccount account): this(account, typeof(T).Name)
    {
    }
    ...
    public IAzureTableRWStrategy ReadWriteStrategy{ get; set; }
    ...
}

Notice that the constructors are not responsible for setting the
read/write strategy and that the type of the ReadWriteStrategy
property is an interface type. You can use property setter injection to
provide an instance of the IAzureTable-RWStrategy type when your
dependency injection container constructs an instance of
AzureTable<T>.

瞩目,那个构造函数不负责安装读/写策略,并且ReadWriteStrategy
属性的门类是接口类型。当您的依赖注入容器构造AzureTable<T>实例时,能够选择性质setter注入来提供IAzureTableRWStrategy项指标实例。

You should only use property setter injection if the class has a usable
default value for the property. While you cannot forget to call a
constructor, you can forget to set a property such as the
ReadWriteStrategy property in the example above.

假如类具有可用的性质的私下认可值,那么相应仅使用性质setter注入。就算你不可能忘却调用构造函数,但您能够淡忘在上面的事例中装置二特性质,如ReadWriteStrategy属性。

You should use property setter injection when the dependency is
optional. However don’t use property setter injection as a technique to
avoid polluting your constructor with multiple dependencies; too many
dependencies might be an indicator of poor design because it is placing
too much responsibility in a single class. See the single responsibility
principle discussed in Chapter 1.

当重视是可选的,你应该运用性质setter注入。但是,不要接纳性质setter注入作为一种技术,以免止污染具备多个依靠的构造函数;
太多的依赖大概是统一筹划不良的2个目标,因为它在二个类中放置了太多的权力和义务。见第3章中切磋的十足权利原则。

However, dependencies are rarely optional when you are building a LOB
application. If you do have an optional dependency, consider using
constructor injection and injecting an empty implementation (the Null
Object Pattern.)

但是当您创设LOB应用程序,正视很少是可选的。就算你有二个可选的依靠项,记挂选取构造函数注入和注入二个空的贯彻(空对象格局)。

Method Call Injection

方法调用注入
In a similar way to using property setter injection, you might want to
invoke a method when the application instantiates an object to perform
some initialization that is not convenient to perform in a constructor.
The following code sample shows part of a class named MessageQueue
in an application that uses method injection to initialize the object.

以近乎的方法使用性质setter注入,当应用程序实例化3个对象以实践1些不便宜在构造函数中举办的起首化时,您恐怕想要调用2个方法。上边实例代码突显了MessageQueue
类的有个别代码,在应用程序中利用办法注入初叶化对象。

public class MessageQueue<T> : ...
{
    ...
    public MessageQueue(StorageAccount account): this(account, typeof(T).Name.ToLowerInvariant())
    {
    }
    public MessageQueue(StorageAccount account, string queueName)
    {
        ...
    }
    public void Initialize(TimeSpan visibilityTimeout,IRetryPolicyFactory retryPolicyFactory)
    {
        ...
    }
    ...
}

In this example, the Initialize method has one concrete parameter
type and one interface parameter type. You can use method injection to
provide an instance of the IRetryPolicyFactory type when your
dependency injection container constructs an instance of
MessageQueue<T>.
Method call injection is useful when you want to provide some additional
information about the context that the object is being used in that
can’t be passed in as a constructor parameter.

在这么些事例中,Initialize
方法有个有血有肉参数类型和一个接口参数类型。当注重注入容器构造MessageQueue<T>实例时,能够用艺术注入来提供IRetryPolicyFactory
类型的实例。

当你想要提供1些有关上下文的附加音信,所采取的对象不可能当做构造函数参数字传送递,方法调用注入是实惠的。

When You Shouldn’t Use Dependency Injection

何时你不应当使用信赖注入
Dependency injection is not a silver bullet. There are reasons for not
using it in your application, some of which are summarized in this
section.
• Dependency injection can be overkill in a small application,
introducing additional complexity and requirements that are not
appropriate or useful.
• In a large application, it can make it harder to understand the code
and what is going on because things happen in other places that you
can’t immediately see, and yet they can fundamentally affect the bit of
code you are trying to read. There are also the practical difficulties
of browsing code like trying to find out what a typical implementation
of the ITenantStore interface actually does. This is particularly
relevant to junior developers and developers who are new to the code
base or new to dependency injection.

• You need to carefully consider if and how to introduce dependency
injection into a legacy application that was not built with inversion of
control in mind. Dependency injection promotes a specific style of
layering and decoupling in a system that may pose challenges if you try
to adapt an existing application, especially with an inexperienced
team.
• Dependency injection is far less important in functional as opposed to
object-oriented programming. Functional programming is becoming a more
common approach when testability, fault recovery, and parallelism are
key requirements.
• Type registration and resolving do incur a runtime penalty: very
negligible for resolving, but more so for registration. However, the
registration should only happen once.

依靠注入不是妙计。在您的应用程序中平素不选择它的因由,当中部分在本节中总括。

  • 借助于注入在小型应用程序中大概是矫枉过正的,引进了不体面或无用的附加复杂性和要求。
  • 在巨型应用程序中,它使得代码更难驾驭和是怎么着,因为东西发身在其余职务,你不能够一向看看,并且它们还也许从根本上影响你尝试阅读的片段代码。
    除此以外还有部分观看代码的其实的困难,比如尝试找出ITenantStore
    接口实际上的正统落到实处。那对于那个对代码库或新的依靠注入新手的低级开发职员和开发职员尤其相关。
  • 您供给细致思虑是否以及怎样将借助注入引进三个不是以反转控制营造的残存应用程序。假使依靠注入在系统中推动特定样式的分层和平化解耦,如若您尝试适应现有应用程序,越发是一贯不经历的组织,可能会带来挑衅。
  • 依靠注入在反效果的面向对象编程是不根本的。当可测试性,故障苏醒和并行性是至关心重视要需求时,功用编制程序正变成越来越宽广的方法。
  • 品类注册和分析会促成运转时惩罚:对于解析是相当卑不足道的,不过越多的是对此注册。但是,注册只应发生贰遍。

Programming languages shape the way we think and the way we code. For a
good exploration of the topic of dependency injection when the
functional programming model is applied, see the article “Dependency
Injection Without the Gymnastics” by Tony Morris.
According to Mark Seeman, using dependency injection “can be dangerous
for your career because it may increase your overall knowledge of good
API design. Once you learn how proper loosely coupled code can look
like, it may turn out that you will have to decline lots of job offers
because you would otherwise have to work with tightly coupled legacy
apps.”
What are the downsides to using Dependency Injection? On StackOverflow.

编制程序语言培养和磨练我们的合计格局和我们的代码的主意。
对于使用函数编制程序模型时信赖注入的宗旨的美貌探索,请参阅托尼Morris的文章“Dependency Injection Without the Gymnastics”。依据马克Seeman,使用注重注入“对您的职业来说也许是危险的,因为它也许扩充你对理想的API设计的完好知识。一旦你学习了什么合适的松弛耦合的代码恐怕会发觉,你将只好拒绝多量的劳作机会,因为您将不得不与严厉耦合的遗留应用程序。”

在StackOverflow上What are the downsides to using Dependency Injection?

Summary

总结
In this chapter, you’ve seen how dependency injection differs from
patterns such as the factory patterns and the service locator pattern by
adopting a push model, whereby some other class or component is
responsible for instantiating the dependencies and injecting them into
your object’s constructor, properties, or methods. This other class or
component is now responsible for composing the application by building
the complete object graph, and in some cases it will also be responsible
for managing the lifetime of the objects that it creates. In the next
chapter, you’ll see how you can use the Unity container to manage the
instantiation of dependent objects and their lifetime.

在本章中,您已经领悟了依靠注入与情势(如工厂格局和服务定位器情势)之间的分别,通过选用推模型,个中部分任何类或机件负责实例化注重关系并将它们注入到对象的构造函数中,
属性或措施。这些别的类或机件未来负责通过创设一体化的靶子图来整合应用程序,在局地状态下还负责管理创设对象的生命周期。在下1章中,你讲看到您能够应用Unity容器去管理正视对象的实例化和他们的生命周期。

More Information

越多音讯
All links in this book are accessible from the book’s online
bibliography available at: http://aka.ms/unitybiblio

本书中的全部链接均可从本书的在线参考书目得到,网站为:http://aka.ms/unitybiblio

http://www.bkjia.com/C\_jc/1201379.htmlwww.bkjia.comtruehttp://www.bkjia.com/C\_jc/1201379.htmlTechArticleUnity文档阅读 第壹章 注重注入,unity第三章
Introduction 介绍 Chapter 一 outlines how you can address some of the
most common requirements in enterprise applications…

介绍
Chapter 1 outlines how you can address some of the most common
requirements in enterprise applications by adopting a loosely coupled
design to minimize the dependencies between the different parts of your
application. However, if a class does not directly instantiate the other
objects that it needs, some other class or component must take on this
responsibility. In this chapter, you’ll see some alternative patterns
that you can use to manage how objects are instantiated in your
application before focusing specifically on dependency injection as the
mechanism to use in enterprise applications.

第二章概述了怎么样通过利用松散耦合设计来最小化应用程序的比不上部分之间的借助关系,从而缓解公司应用程序中的壹些最广大的须求。但是,假使叁个类不直接实例化它需求的别的对象,一些任何类或机件必须担当这几个义务。在本章中,您将见到有的可用于管理对象在应用程序中怎样实例化的替代形式,在您肯定你的公司应用使用的话注入机制以前。

Factories, Service Locators, and Dependency Injection

工厂、服务一定和依赖性注入 Factories, service locators, and dependency injection are all
approaches you can take to move the responsibility for instantiating and
managing objects on behalf of other client objects. In this section,
you’ll see how you can use them with the same example you saw in the
previous chapter. You’ll also see the pros and cons of the different
approaches and see why dependency injection can be particularly useful
in enterprise applications.

厂子、服务一定和信赖性注入是你能够运用的保有路线,用于转移替代别的客户对象实例化和管理对象的职分。在本节中,您将看到什么样运用上1章中所示的示范。您还将见到差异措施的利弊,并询问怎么依赖注入在集团应用程序中特地有用。

Factory Patterns

工厂情势
There are three common factory patterns. The Factory Method and Abstract
Factory patterns from “Design Patterns: Elements of Reusable
Object-Oriented Software” by Gamma, Erich, Richard Helm,Ralph Johnson,
and John Vlissides. Addison Wesley Professional, 1994., and the Simple
Factory pattern.

有两种普遍的工厂方式。工厂方法和架空工厂情势来自Gamma, 埃里克h, RichardHelm,拉尔夫 Johnson, and John Vlissides.艾狄生 韦斯利 Professional,
壹9九伍“设计方式:可选拔的面向对象软件的成分”,和精炼工厂方式。

The Factory Method Pattern

厂子方法方式
The following code samples show how you could apply the factory method
pattern to the example shown in the previous chapter. The first code
sample shows how you could use a factory method to return an instance of
the TenantStore class to use in the ManagementController class.
In this example, the CreateTenantStore method is the factory method
that creates the TenantStore instance and the Index method uses
this instance as part of its logic.

以下代码示例展现怎么将工厂方法形式接纳于上一章中所示的言传身教。第一段代码示例演示怎样利用工厂方法重返ManagementController
类中央银行使的TenantStore 类的实例。在这一个示例中,CreateTenantStore
方法是二个创设TenantStore
示例的厂子方法,Index主意运用此实例作为其论理的壹有的。

public class ManagementController : Controller
{
    protected ITenantStore tenantStore;
    public ManagementController()
    {
        this.tenantStore = CreateTenantStore();
    }
    protected virtual ITenantStore CreateTenantStore()
    {
        var storageAccount = AppConfiguration.GetStorageAccount("DataConnectionString");
        var tenantBlobContainer = new EntitiesContainer<Tenant>(storageAccount, "Tenants");
        var logosBlobContainer = new FilesContainer(storageAccount, "Logos", "image/jpeg");
        return new TenantStore(tenantBlobContainer, logosBlobContainer);
    }
    public ActionResult Index()
    {
        var model = new TenantPageViewData<IEnumerable<string>>(this.tenantStore.GetTenantNames())
        {
            Title = "Subscribers"
        };
        return this.View(model);
    }
    ...
}

Using this approach does not remove the dependencies the
Management-Controller has on the TenantStore class, nor the
FilesContainer and Entities-Container classes. However, it is
now possible to replace the underlying storage mechanism without
changing the existing ManagementController class as the following
code sample shows.

接纳那种格局不能够去除ManagementControllerTenantStore
类的看重,也不会去除FilesContainer和EntitiesContainer类。然而,他明天得以轮换底层的积存机制而不用更改现有的ManagementController
类,就好像下边代码所示范的。

public class SQLManagementController : ManagementController
{
    protected override ITenantStore CreateTenantStore()
    {
        var storageAccount = ApplicationConfiguration.GetStorageAccount("DataConnectionString");
        var tenantSQLTable = ...
        var logosSQLTable = ....
        return new SQLTenantStore(tenantSQLTable, logosSQLTable);
    }
    ...
}

The factory method pattern enables you to modify the behavior of a class
without modifying the class itself by using inheritance.

应用持续,工厂方法允许你修改类的一言一动,而无需修改类自个儿。

The application can use the SQLManagementController class to use a
SQL-based store without you needing to make any changes to the original
ManagementController class. This approach results in a flexible and
extensible design and implements the open/closed principle described in
the previous chapter. However, it does not result in a maintainable
solution because all the client classes that use the TenantStore
class are still responsible for instantiating TenantStore instances
correctly and consistently.

那些利用能够行使SQLManagementController 类去行使SQLbased
存款和储蓄,未有在原ManagementController
类中做别的修改。那种格局导致灵活和可增添的统一筹划,并完成前一章中讲述的开/闭原理。不过,它不会产生可保证的消除方案,因为使用TenantStore
类全体的客户类还是承担任正角色确和同样的实例化TenantStore 实例。

It is also still difficult to test the ManagementController class
because it depends on the TenantStore type, which in turn is tied to
specific storage types (FilesContainer and EntitiesContainer).
One approach to testing would be to create a
MockManagementController type that derives from
Management-Controller and that uses a mock storage implementation to
return test data: in other words you must create two mock types to
manage the testing.

ManagementController 类的测试仍旧是不方便的,因为它借助TenantStore
类型,而那又凭借于特定的储存类型(FilesContainer
EntitiesContainer)。1种测试方法是创办三个来自ManagementControllerMockManagementController花色,并运用模拟存储实现重回测试数据:换句话说,您必须创设八个模拟类型来治本测试。

In this example, there is an additional complication because of the way
that ASP.NET MVC locates controllers and views based on a naming
convention: you must also update the MVC routes to ensure that MVC uses
the new SQLManagementController class.

在那一个示例中,还有二个额外的复杂,因为ASP.NET
MVC基于命名约定定位控制器和视图的方法:你不洗还要修改MVC的路由去保障MVC使用新的SQLManagementController
类。

Simple Factory Pattern

简简单单工厂情势
While the factory method pattern does not remove the dependencies from
the high-level client class, such as the ManagementController class,
on the low-level class, you can achieve this with the simple factory
pattern. In this example, you can see that a new factory class named
TenantStoreFactory is now responsible for creating the
TenantStore instance on behalf of the ManagementController
class.

纵然工厂方法情势不能够从底层类中移除高层客户类(ManagementController
类)的依赖,但足以行使简便的厂子形式完毕此目标。在那个示例中,你能够看来名叫TenantStoreFactory
的新工厂类,现在承担代表ManagementController 类创建TenantStore
的实例。

public class ManagementController : Controller
{
    private readonly ITenantStore tenantStore;
    public ManagementController()
    {
        var tenantStoreFactory = new TenantStoreFactory();
        this.tenantStore = tenantStoreFactory.CreateTenantStore();
    }
    public ActionResult Index()
    {
        var model = new TenantPageViewData<IEnumerable<string>>(this.tenantStore.GetTenantNames())
        {
            Title = "Subscribers"
        };
        return this.View(model);
    }
    ...
}

The simple factory pattern removes the direct dependency of the
Management-Controller class on a specific store implementation.
Instead of including the code needed to build a TenantStore instance
directly, the controller class now relies on the TenantStoreFactory
class to create the instance on its behalf.

本条差不离工厂形式移除了ManagementController
对特定期存款款和储蓄达成的第壹手信赖。而不是一向包涵营造TenantStore实例所需的代码,控制器类将来依靠TenantStoreFactory
类来表示其创设实例。

Abstract Factory Pattern

空泛工厂情势
One of the problems that can arise from using the simple factory pattern
in a large application is that it can be difficult to maintain
consistency. For example, the application may include multiple store
classes such as SurveyStore, LogoStore, and ReportStore
classes in addition to the TenantStore class you’ve seen in the
examples so far. You may have a requirement to use a particular type of
storage for all of the stores. Therefore, you could implement a
BlobStoreFactory abstract factory class that can create multiple
blob-based stores, and a SQLStoreFactory abstract factory class that
can create multiple SQL based stores.

在巨型应用程序中采用简便工厂方式恐怕发生的题材之一是大概麻烦维持一致性。例如,除了您在演示中来看的TenantStore类之外,应用程序还能总结四个商店类,例如SurveyStoreLogoStoreReportStore类。您可能供给为拥有存款和储蓄使用一定类型的积存。因而,你可以兑现BlobStoreFactory
抽象工厂类创造多少个基于blob的存款和储蓄,和促成SQLStoreFactory
抽象工厂类创制多个基于SQL的贮存。

The abstract factory pattern is described in “Design Patterns: Elements
of Reusable Object-Oriented Software” by Gamma, et al.

抽象工厂方式在Gamma等人的“设计情势:可复用面向对象软件的规律”中描述。

The abstract factory pattern is useful if you have a requirement to
create families of related objects in a consistent way.

假定您须要以平等的措施开创连锁对象的族,则抽象工厂形式很有用。

Service Locator Pattern

服务一定方式
Using a service locator provides another variation to this general
approach of using another class to create objects on your behalf. You
can think of a service locator as a registry that you can look up an
instance of an object or service that another class in your application
created and registered with the service locator. The service locator
might support querying for objects by a string key or by interface type.
Often, in contrast to the factory patterns where the factory creates the
object but gives responsibility for managing its lifetime to the client
class, the service locator is responsible for managing the lifetime of
the object and simply returns a reference to the client. Also, factories
are typically responsible for creating instances of specific types or
families of types as in the case of the abstract factory pattern, while
a service locator may be capable of returning a reference to an object
of any type in the application.

应用劳务一定提供了相似方法应用另一个类地代表你创造对象的另一个生成。你能够认为服务一定便是注册表,那样你能够搜寻对象或服务的实例,应用程序中的另3个类成立并登记到劳动定位器。服务一定也能协理根据字符串的主键或接口类型查询对象。经常,与工厂创造对象,可是客户代码负责管理对象的生命周期的工厂情势相反,服务一定负责管理对象的生命周期,只回去引用到客户端。别的,工厂经常负责创制特定项目或项目标实例的实例,如在架空工厂情势的情形下,而服务定位器能够能够回到对利用中别的项指标对象的引用。

The section “Object Lifetime” later in this chapter discusses object
lifetimes in more detail.

本节背后的“对象生命周期”部分更详实地谈论对象生命周期。

Any classes that retrieve object references or service references from
the service locator will have a dependency on the service locator
itself.
For a description of the service locator pattern, see the section “Using
a Service Locator” in the article “Inversion of Control Containers and
the Dependency Injection pattern” by Martin Fowler.

其余类从劳动一定中追寻对象引用或劳动应用,都将借助服务一定它自己。

服务一定情势的3个描述,请看马丁 Fowler写的稿子“Inversion of Control
Containers and the Dependency Injection pattern”中的“Using a ServiceLocator”章节.

For a discussion of why the service locator may be considered an
anti-pattern, see the blog post “Service Locator is an Anti-Pattern” by
Mark Seeman.
For a shared interface for service location that application and
framework developers can reference, see the Common Service Locator
library. The library provides an abstraction over dependency injection
containers and service locators. Using the library allows an application
to indirectly access the capabilities without relying on hard
references.

议论为啥服务定位器可能被认为是1种反方式,请看马克Seeman公布的博客“Service Locator is an Anti-帕特tern”。

对于应用程序和框架开发职员能够引用的劳动一定的共享接口,请参阅Common
ServiceLocator库。库提供了对依赖注入容器和劳务定位器的悬空。使用库允许应用程序直接访问效率而不依靠于硬引用。

When using a service locator, every class will have a dependency on your
service locator. This is not the case with dependency injection.

当使用服务一定,每个类都将借助你的劳务一定。那不是注重注入的情景。

Dependency Injection

依傍注入
A common feature of the all the factory patterns and the service locator
pattern, is that it is still the high-level client object’s
responsibility to resolve its own dependencies by requesting the
specific instances of the types that it needs. They each adopt a pull
model of varying degrees of sophistication, assigning various
responsibilities to the factory or service locator. The pull model also
means that the high-level client class has a dependency on the class
that is responsible for creating or locating the object it wants to use.
This also means that the dependencies of the high-level client classes
are hidden inside of those classes rather specified in a single
location, making them harder to test.
Figure 1 shows the dependencies in the simple factory pattern where the
factory instantiates a TenantStore object on behalf of the
ManagementController class.

抱有工厂情势和劳务定位器形式的2个1起天性是,它依旧须要高层客户对象承担通过请求它所必要的特定实体类型来缓解它自身的正视关系。它们分别行使不一致水平的复杂度的拉模型,将分歧的职责分配给工厂或服务定位器。拉取模型意味着高层客户类有负责创立或一定它想要使用的对象的依靠。那也表示高等客户端类的注重隐藏在那个类中,而是在单个地方中内定,那使得它们更麻烦测试。

图形一显得简单工厂情势在象征ManagementController
类创制实例化TenantStore 对象的依靠关系。

永利会娱乐 1

图形一 在工厂格局中的正视

Dependency injection takes the opposite approach, adopting a push model
in place of the pull model. Inversion of Control is a term that’s often
used to describe this push model and dependency injection is one
specific implementation of the inversion of control technique.
Martin Fowler states: “With service locator the application class asks
for it explicitly by a message to the locator. With injection there is
no explicit request, the service appears in the application class—hence
the inversion of control.” (Inversion of Control Containers and the
Dependency Injection
pattern
.)
With dependency injection, another class is responsible for injecting
(pushing) the dependencies into the high-level client classes, such as
the Management-Controller class, at runtime. The following code
sample shows what the high-level ManagementController class looks
like if you decide to use dependency injection.

依靠注入采取相反的章程,选择推模型代替拉模型。控制反转是二个常用来描述推模型的术语,依赖注入是控制反转技术的3个具体实现。

马丁Fowler写明:“使用劳务定位器,应用程序类通过到定位器的新闻显式地请求它。
使用注入未有强烈的伸手,服务出现在应用程序类中 –
由此反转控制。”(Inversion of Control Containers and the Dependency
Injection
pattern
.)

用信赖注入,另二个类负责在运作时注入(推送)重视性到高层客户类,如Management-Controller类。以下代码示例彰显了假设你决定使用注重注入,高级ManagementController类的容颜。

public class ManagementController : Controller
{
    private readonly ITenantStore tenantStore;
    public ManagementController(ITenantStore tenantStore)
    {
        this.tenantStore = tenantStore;
    }
    public ActionResult Index()
    {
        var model = new TenantPageViewData<IEnumerable<string>>(this.tenantStore.GetTenantNames())
        {
            Title = "Subscribers"
        };
    return this.View(model);
    }
    ...
}

As you can see in this sample, the ManagementController constructor
receives an ITenantStore instance as a parameter, injected by some
other class. The only dependency in the ManagementContoller class is
on the interface type. This is better because it doesn’t have any
knowledge of the class or component that is responsible for
instantiating the ITenantStore object.
In Figure 2, the class that is responsible for instantiating the
TenantStore object and inserting it into the
ManagementController class is called the
Dependency-InjectionContainer class.

正如你所见到的这么些示例,ManagementController
构造函数接收三个ITenantStore
实例参数,由其它类注入。ManagementContoller
类仅仅凭借二个接口类型。那样是越来越好地,因为它不供给有担当实例化ITenantStore对象的类或机件的别的文化。

在图纸第22中学,负责实例化TenantStore指标并将其插入到ManagementController类中的类称为DependencyInjectionContainer类。

永利会娱乐 2

图形二 当使用正视注入的重视性关系

Chapter 3, “Dependency Injection with Unity,” will describe in more
detail what happens in the DependencyInjectionContainer class

章节3,“用Unity重视注入”,将越发详细的描述DependencyInjectionContainer
类中发生了什么样。

The key difference between the Figure 1 and Figure 2 is the direction of
the dependency from the ManagementController class. In Figure 2, the
only dependency the ManagementController class has is on the
ITenantStore interface.

图片1和图形二的第二差距在来自ManagementController
类的正视性方向上。图形第22中学ManagementController
类仅仅依靠ITenantStore 接口。

Object Composition

对象组成
So far in this chapter, you have seen how dependency injection can
simplify classes such as the ManagementController class and minimize
the number of dependencies between classes in your application. The
previous chapter explained some of the benefits of this approach, such
as maintainability and testability, and showed how this approach relates
to the SOLID principles of object-oriented programming. You will now see
how this might work in practice: in particular, how and where you might
use dependency injection in your own applications.

到本章如今停止,你早已见到正视注入怎么着简化类,如ManagementController类,并最小化应用程序中的类之间的信赖性关系的数量。前一章解释了部分那种办法的好处,比如可维护性和可测试性,并且出示了该措施怎样与SOLID原则的面向对象编制程序相关。你未来得以看到那在具体中怎么着能够干活的:尤其是,在你自个儿的应用程序中您能够行使重视注入的诀窍和岗位。

In Figure 2, the DependencyInjectionContainer class may manage the
dependencies of multiple high level client classes such as the
Management-Controller class on multiple service classes such as the
TenantStore class.
You can use either a dependency injection container or implement
dependency injection manually using factories. As you’ll see in the next
chapter, using a container is easier and provides additional
capabilities such as lifetime management, interception, and registration
by convention.

在图形2中,DependencyInjectionContainer
类能够管理高层客户类的多个依靠,例如ManagementController
类上有四个服务类,比如TenantStore 类。

您能够你能够使用信赖注入容器也许利用工厂手工业达成依靠注入。正如你在下已章节看到的,使用容器是更简约的,并提供附加效能,如生命周期管理、拦截和平条约定注册。

If you adopt the dependency injection approach, you will have many
classes in your application that require some other class or component
to pass the necessary dependencies into their constructors or methods as
parameters or as property values before you can use them. This implies
that your application requires a class or component that is responsible
for instantiating all the required objects and passing them into the
correct constructors, methods, and properties: your application must
know how to compose its object graph before it can perform any work.
This must happen very early in the application’s lifecycle: for example,
in the Main method of a console application, in the Global.asax
in a web application, in a role’s OnStart method in a Windows Azure
application, or in the initialization code for a test method.

比方你利用依赖注入方式,在您的应用程序中您将有恒河沙数类,供给有的别样类或机件将要求的依赖传递到构造函数或格局作为参数或属性值,然后你才能运用它们。那就以为这你的应用程序须要二个类或机件是肩负实例化全部必要的靶子并将它们传递到科学的构造函数,方法和性子:你的应用程序必须掌握怎么怎么样去组成他的目的图,在能够执行别的工作前。那必须在应用程序的生命周期的最初发生:比如,在控制台程序的Main办法中,Web应用程序的Global.asax
Windows Azure 应用程序中的剧中人物的OnStart
方法中,大概在测试方法的伊始化代码中。

Typically, you should place all the code tells the application how to
build its object graph in a single location; this is known as the
Composition Root pattern. This makes it much easier to maintain and
update the application.

常备,您应该将持有代码告诉应用程序如何在单个地点创设其指标图;
那被喻为组合根形式。那使得应用程序维护和创新尤其简约。

Object Lifetime

对象生命周期
You should determine when to create the objects in your application
based on criteria such as which object is responsible for managing the
state, is the object shared, and how long the object will live for.
Creating an object always takes a finite amount of time that is
determined by the object’s size and complexity, and once you have
created an object, it occupies some of your system’s memory.
在你的应用程序中你应当依照原则(如哪个指标负责管理状态、是或不是共享对象以及对象能够共存多短时间)决定何时去创立对象。创设对象总是必要不难的年月,由对象的分寸和错综复杂决定,1旦创设了目的,它就占用了系统的有的内部存款和储蓄器。

In the example, you’ve seen in this chapter, there is a single
Management-Controller client class that uses an implementation of
the ITenantStore interface. In a real application, there may be many
other client classes that all need ITenantStore instances. Depending
on the specific requirements and structure of your application, you
might want each client class to have its own ITenantStore object, or
have all the client classes share the same ITenantStore instance, or
for different groups of client classes each have their own
ITenantStore instance.

在本章的例子中你早就看到,有一个ManagementController客户类使用二个ITenantStore
的实例。在实际的应用程序中,那里大概有众多任何客户类都须要ITenantStore
的实例。根据你应用程序的特殊需求和数据结构,你大概想要各类客户类都有投机的ITenantStore
对象,或偶有的客户类共享相同的ITenantStore
实例,或每一种区别的客户类组有本人的ITenantStore 实例。

If every client object has its own ITenantStore instance, then the
ITenantStore instance can be garbage collected along with the client
object. If multiple client objects share an ITenantStore instance,
then the class or component that instantiates the shared
ITenantStore object must responsible for tidying it up when all the
clients are finished with it.

一旦各样客户对象都有协调的ITenantStore
实例,则ITenantStore实例能够与客户端对象1起举行垃圾回收。如若多少个客户对象共享2个ITenantStore
实例,则类或机件实例化共享的ITenantStore
对象必须承受在拥有客户端实现它后对其进展整治。

Whichever way you create an object, there is always a trade-off between
performance and resource utilization when you decide where to
instantiate it.

永利会娱乐,任凭以何种方法创造对象,在决定在哪儿实例化它时,在性质和能源利用率之间连接存在权衡。

Types of Injection

流入类型
Typically, when you instantiate an object you invoke a class constructor
and pass any values that the object needs as parameters to the
constructor. In the example that you saw earlier in this chapter, the
constructor in the Management-Controller class expects to receive an
object that implements the ITenantStore interface. This is an
example of constructor injection and is the type of injection you will
use most often. There are other types of injection such as property
setter injection and method call injection, but they are less commonly
used.

壹般说来,当你实例化2个指标时,您调用贰个类构造函数,并将该目的须要的别的值作为参数字传送递给构造函数。在本章前边的例子中您看到,ManagementController
类中的构造函数供给接受实现了ITenantStore
接口的目的。这是四个构造函数注入的例证,是你最常使用的注入类型。还有别的的有个别注入类型,比如属性设置注入和艺术调用注入,然而她们1般接纳的可比少。

Property Setter Injection

属性设置注入
As an alternative or in addition to passing a parameter to a
constructor, you may want to set a property value when you instantiate
an object in your application. The following code sample shows part of a
class named AzureTable in an application that uses property
injection to set the value of the ReadWrite-Strategy property when
it instantiates AzureTable object.

作为向构造函数传递参数的替代格局或补给措施,您恐怕供给在应用程序中实例化对象时设置属性值。以下代码示例呈现了应用程序中名叫AzureTable的类的一有的,在实例化AzureTable目的时,它选拔性质注入来安装ReadWriteStrategy质量的值。

public class AzureTable<T> : ...
{
    public AzureTable(StorageAccount account): this(account, typeof(T).Name)
    {
    }
    ...
    public IAzureTableRWStrategy ReadWriteStrategy{ get; set; }
    ...
}

Notice that the constructors are not responsible for setting the
read/write strategy and that the type of the ReadWriteStrategy
property is an interface type. You can use property setter injection to
provide an instance of the IAzureTable-RWStrategy type when your
dependency injection container constructs an instance of
AzureTable<T>.

留神,这些构造函数不负担安装读/写策略,并且ReadWriteStrategy
属性的花色是接口类型。当您的重视注入容器构造AzureTable<T>实例时,能够利用性质setter注入来提供IAzureTableRWStrategy花色的实例。

You should only use property setter injection if the class has a usable
default value for the property. While you cannot forget to call a
constructor, you can forget to set a property such as the
ReadWriteStrategy property in the example above.

假定类具有可用的品质的暗中同意值,那么相应仅使用性质setter注入。尽管你无法忘掉调用构造函数,但您能够淡忘在地方的事例中安装三个属性,如ReadWriteStrategy属性。

You should use property setter injection when the dependency is
optional. However don’t use property setter injection as a technique to
avoid polluting your constructor with multiple dependencies; too many
dependencies might be an indicator of poor design because it is placing
too much responsibility in a single class. See the single responsibility
principle discussed in Chapter 1.

当注重是可选的,你应该使用性质setter注入。不过,不要选择品质setter注入作为1种技术,以制止污染具备多个依靠的构造函数;
太多的正视可能是统一筹划不良的三个目的,因为它在三个类中放置了太多的权力和义务。见第三章中商量的10足义务标准。

However, dependencies are rarely optional when you are building a LOB
application. If you do have an optional dependency, consider using
constructor injection and injecting an empty implementation (the Null
Object Pattern.)

不过当你营造LOB应用程序,正视很少是可选的。假诺您有二个可选的依靠项,考虑使用构造函数注入和注入三个空的兑现(空对象情势)。

Method Call Injection

措施调用注入
In a similar way to using property setter injection, you might want to
invoke a method when the application instantiates an object to perform
some initialization that is not convenient to perform in a constructor.
The following code sample shows part of a class named MessageQueue
in an application that uses method injection to initialize the object.

以近乎的不二诀窍采用品质setter注入,当应用程序实例化2个指标以推行一些不便利在构造函数中实践的开端化时,您只怕想要调用二个措施。下边实例代码呈现了MessageQueue
类的部分代码,在应用程序中应用办法注入初叶化对象。

public class MessageQueue<T> : ...
{
    ...
    public MessageQueue(StorageAccount account): this(account, typeof(T).Name.ToLowerInvariant())
    {
    }
    public MessageQueue(StorageAccount account, string queueName)
    {
        ...
    }
    public void Initialize(TimeSpan visibilityTimeout,IRetryPolicyFactory retryPolicyFactory)
    {
        ...
    }
    ...
}

In this example, the Initialize method has one concrete parameter
type and one interface parameter type. You can use method injection to
provide an instance of the IRetryPolicyFactory type when your
dependency injection container constructs an instance of
MessageQueue<T>.
Method call injection is useful when you want to provide some additional
information about the context that the object is being used in that
can’t be passed in as a constructor parameter.

在那么些例子中,Initialize
方法有个实际参数类型和2个接口参数类型。当信赖注入容器构造MessageQueue<T>实例时,能够用艺术注入来提供IRetryPolicyFactory
类型的实例。

当您想要提供部分关于上下文的额外音信,所选取的对象无法同日而语构造函数参数字传送递,方法调用注入是实用的。

When You Shouldn’t Use Dependency Injection

曾几何时你不应该运用注重注入
Dependency injection is not a silver bullet. There are reasons for not
using it in your application, some of which are summarized in this
section.
• Dependency injection can be overkill in a small application,
introducing additional complexity and requirements that are not
appropriate or useful.
• In a large application, it can make it harder to understand the code
and what is going on because things happen in other places that you
can’t immediately see, and yet they can fundamentally affect the bit of
code you are trying to read. There are also the practical difficulties
of browsing code like trying to find out what a typical implementation
of the ITenantStore interface actually does. This is particularly
relevant to junior developers and developers who are new to the code
base or new to dependency injection.

• You need to carefully consider if and how to introduce dependency
injection into a legacy application that was not built with inversion of
control in mind. Dependency injection promotes a specific style of
layering and decoupling in a system that may pose challenges if you try
to adapt an existing application, especially with an inexperienced
team.
• Dependency injection is far less important in functional as opposed to
object-oriented programming. Functional programming is becoming a more
common approach when testability, fault recovery, and parallelism are
key requirements.
• Type registration and resolving do incur a runtime penalty: very
negligible for resolving, but more so for registration. However, the
registration should only happen once.

借助注入不是妙招。在你的应用程序中尚无动用它的原由,此中部分在本节中总计。

  • 重视注入在小型应用程序中恐怕是矫枉过正的,引进了不对路或无用的额外复杂性和须求。
  • 在大型应用程序中,它使得代码更难了然和是如何,因为东西发身在其余地点,你不能够直接看到,并且它们还恐怕从根本上海电影制片厂响您尝试阅读的局地代码。
    除此以外还有局地阅读代码的实际上的诸多不便,比如尝试找出ITenantStore
    接口实际上的正经落到实处。那对于那叁个对代码库或新的依靠注入新手的低级开发人士和开发职员越发相关。
  • 您必要细致思虑是或不是以及哪些将凭借注入引进2个不是以反转控制创设的遗留应用程序。假如借助注入在系统中拉动特定样式的分层和平解决耦,假诺您尝试适应现有应用程序,尤其是尚未经历的协会,可能会推动挑战。
  • 凭借注入在反效果的面向对象编程是不根本的。当可测试性,故障苏醒和并行性是重大供给时,成效编制程序正成为更广阔的情势。
  • 品种注册和剖析会招致运维时惩罚:对于解析是不行卑不足道的,不过越多的是对于注册。不过,注册只应发生壹遍。

Programming languages shape the way we think and the way we code. For a
good exploration of the topic of dependency injection when the
functional programming model is applied, see the article “Dependency
Injection Without the
Gymnastics

by Tony Morris.
According to Mark Seeman, using dependency injection “can be dangerous
for your career because it may increase your overall knowledge of good
API design. Once you learn how proper loosely coupled code can look
like, it may turn out that you will have to decline lots of job offers
because you would otherwise have to work with tightly coupled legacy
apps.”
What are the downsides to using Dependency
Injection
?
On StackOverflow.

编制程序语言培养大家的盘算格局和我们的代码的模式。
对于使用函数编制程序模型时正视注入的大旨的好好探索,请参阅TonyMorris的稿子“Dependency Injection Without the
Gymnastics
”。根据MarkSeeman,使用依赖注入“对你的差事来说或然是惊险的,因为它或然扩大你对优质的API设计的完全知识。一旦你学习了何等适当的松懈耦合的代码可能会发觉,你将只可以拒绝大批量的做事机遇,因为您将不得不与严苛耦合的残存应用程序。”

在StackOverflow上What are the downsides to using Dependency
Injection

Summary

总结
In this chapter, you’ve seen how dependency injection differs from
patterns such as the factory patterns and the service locator pattern by
adopting a push model, whereby some other class or component is
responsible for instantiating the dependencies and injecting them into
your object’s constructor, properties, or methods. This other class or
component is now responsible for composing the application by building
the complete object graph, and in some cases it will also be responsible
for managing the lifetime of the objects that it creates. In the next
chapter, you’ll see how you can use the Unity container to manage the
instantiation of dependent objects and their lifetime.

在本章中,您已经理解了信赖注入与方式(如工厂方式和劳务定位器格局)之间的区分,通过使用推模型,在那之中1些别的类或机件负责实例化依赖关系并将它们注入到对象的构造函数中,
属性或方式。这些其余类或机件未来承担通过构建完全的目的图来组合应用程序,在1些场馆下还负责管理创制对象的生命周期。在下一章中,你讲看到你能够动用Unity容器去管理注重对象的实例化和她们的生命周期。

More Information

越多音讯
All links in this book are accessible from the book’s online
bibliography available at: http://aka.ms/unitybiblio

本书中的所有链接均可从本书的在线参考书目获得,网站为:http://aka.ms/unitybiblio

相关文章