厂子、服务一定和凭借注入,您将见到1些可用于管理对象在应用程序中哪些实例化的替代情势

Introduction

Unity文书档案阅读 第二章 依赖注入,unity第3章

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.

厂子、服务一定和信赖注入是您能够运用的拥有途径,用于转移替代其余客户对象实例化和管理对象的天职。在本节中,您将见到哪些使用上壹章中所示的演示。您还将看到不一样措施的利弊,并打听怎么信赖注入在公司应用程序中特地有用。

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.Addison 韦斯利 Professional,
一玖玖伍“设计情势:可选取的面向对象软件的成分”,和省略工厂格局。

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
方法是三个创办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
类中做别的修改。那种艺术导致灵活和可增添的统一筹划,并达成前1章中讲述的开/闭原理。但是,它不会发生可保证的消除方案,因为使用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)。一种测试方法是创设3个来自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.

在那一个示例中,还有2个格外的复杂,因为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.

任何类从服务一定中寻找对象引用或劳动使用,都将借助服务一定它本人。

服务一定情势的三个描述,请看Martin 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发布的博客“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.

具有工厂形式和服务定位器形式的3个一同性子是,它照旧要求高层客户对象承担通过请求它所急需的特定实体类型来消除它和谐的依靠关系。它们各自行使差别档次的复杂度的拉模型,将区别的权利分配给工厂或服务定位器。拉取模型意味着高层客户类有负责成立或定点它想要使用的靶子的信赖性。那也意味着高等客户端类的依靠隐藏在这几个类中,而是在单个地方中内定,那使得它们更难以测试。

图形一呈现简单工厂形式在象征ManagementController
类创造实例化TenantStore 对象的重视性关系。

图形一 在工厂格局中的信赖

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.

依靠注入选择相反的办法,选择推模型代替拉模型。控制反转是二个常用来描述推模型的术语,依赖注入是控制反转技术的二个具体贯彻。

MartinFowler写明:“使用服务定位器,应用程序类通过到定位器的音信显式地央浼它。
使用注入未有强烈的伸手,服务出现在应用程序类中 –
因而反转控制。”(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
构造函数接收3个ITenantStore
实例参数,由别的类注入。ManagementContoller
类仅仅依靠3个接口类型。那样是越来越好地,因为它不须求有负责实例化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.

要是你选取依赖注入格局,在您的应用程序中您将有成都百货上千类,要求有的别样类或机件将供给的依靠传递到构造函数或格局作为参数或属性值,然后你才能运用它们。那就以为那你的应用程序须求三个类或机件是肩负实例化全数要求的指标并将它们传递到科学的构造函数,方法和总体性:你的应用程序必须精晓怎么怎样去组成他的目的图,在能够推行此外工作前。那必须在应用程序的生命周期的早期爆发:比如,在控制台程序的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.

在本章的例证中您曾经观察,有3个ManagementController客户类应用3个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实例能够与客户端对象一起展开垃圾回收。假使多少个客户对象共享贰个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.

1般性,当你实例化三个对象时,您调用三个类构造函数,并将该指标急需的任何值作为参数字传送递给构造函数。在本章前边的事例中你见到,ManagementController
类中的构造函数须求收取完毕了ITenantStore
接口的目的。那是一个构造函数注入的例子,是您最常使用的流入类型。还有别的的一部分注入类型,比如属性设置注入和措施调用注入,不过他们一般选用的可比少。

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注入作为壹种技术,避防止污染具备三个依靠的构造函数;
太多的依赖恐怕是统一筹划不良的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应用程序,信赖很少是可选的。假使你有三个可选的依靠项,思索采纳构造函数注入和注入1个空的达成(空对象方式)。

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
方法有个具体参数类型和贰个接口参数类型。当重视注入容器构造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
    接口实际上的正儿捌经兑现。这对于那一个对代码库或新的正视注入新手的起码开发职员和开发职员尤其相关。
  • 你供给仔细思虑是否以及怎么着将借助注入引入1个不是以反转控制营造的残存应用程序。借使依靠注入在系统中有助于特定样式的分支和平消除耦,假如你尝试适应现有应用程序,越发是未曾经验的集体,也许会带来挑衅。
  • 借助注入在反效果的面向对象编制程序是不重大的。当可测试性,故障复苏和并行性是关键供给时,成效编制程序正成为越来越宽广的主意。
  • 品种注册和分析会导致运营时惩罚:对于解析是可怜微不足道的,不过更多的是对于注册。不过,注册只应发生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些任何类或机件负责实例化正视关系并将它们注入到对象的构造函数中,
属性或措施。这些其余类或机件现在负责通过构建一体化的靶子图来整合应用程序,在局地状态下还负责管理创制对象的生命周期。在下一章中,你讲看到你可以应用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文档阅读 第3章 正视注入,unity第1章
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.

第2章概述了如何通过利用松散耦合设计来最小化应用程序的不等部分之间的借助关系,从而解决集团应用程序中的壹些最广泛的必要。不过,假诺七个类不直接实例化它要求的其他对象,壹些别样类或机件必须承担那些义务。在本章中,您将见到局地可用于管理对象在应用程序中怎么着实例化的替代形式,在您肯定你的公司应用使用的话注入机制在此之前。

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,Ralph Johnson, and John Vlissides.Addison 韦斯利 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)。一种测试方法是开创叁个来自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.

在那个示例中,还有3个非凡的繁杂,因为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.

选取劳务一定提供了貌似方法应用另1个类地代表你成立对象的另二个变迁。你能够认为劳动一定便是注册表,那样你可以查找对象或服务的实例,应用程序中的另三个类创立并登记到劳动定位器。服务一定也能支撑依据字符串的主键或接口类型查询对象。平常,与工厂创制对象,然而客户代码负责管理对象的生命周期的厂子情势相反,服务一定负责管理对象的生命周期,只回去引用到客户端。其它,工厂平常负责创制特定项目或项目标实例的实例,如在架空工厂方式的状态下,而服务定位器能够能够回到对利用中其余类型的目的的引用。

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发布的博客“Service Locator is an Anti-Pattern”。

对此应用程序和框架开发职员能够引用的服务一定的共享接口,请参阅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.

抱有工厂情势和劳务定位器形式的3个体协会同特征是,它照旧供给高层客户对象承担通过请求它所急需的一定实体类型来缓解它和谐的注重关系。它们分别行使不一致程度的复杂度的拉模型,将区别的义务分配给工厂或劳务定位器。拉取模型意味着高层客户类有担当创制或一定它想要使用的目的的信赖。那也表示高等客户端类的正视隐藏在这么些类中,而是在单个地方中钦赐,那使得它们更麻烦测试。

图片壹来得简单工厂形式在代表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.

依赖注入选用相反的主意,采取推模型代替拉模型。控制反转是1个常用来讲述推模型的术语,依赖注入是决定反转技术的二个切实可行落到实处。

马丁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
类仅仅依赖3个接口类型。那样是越来越好地,因为它不需求有担当实例化ITenantStore对象的类或机件的别样文化。

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

图片 2

图表二 当使用依赖注入的信赖关系

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.

图片一和图形二的主要性分化在来源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客户类应用2个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个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
接口的靶子。那是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个目的,因为它在叁个类中放置了太多的权力和义务。见第叁章中商讨的纯粹权利标准。

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应用程序,正视很少是可选的。假诺你有一个可选的借助项,思量动用构造函数注入和注入3个空的落到实处(空对象形式)。

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注入,当应用程序实例化一个对象以执行一些不便于在构造函数中进行的初步化时,您或许想要调用一个格局。上边实例代码展现了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
方法有个具体参数类型和3个接口参数类型。当重视注入容器构造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.

借助于注入不是妙招。在您的应用程序中平素不利用它的原故,在那之中1些在本节中计算。

  • 凭借注入在小型应用程序中或然是矫枉过正的,引进了不适宜或无用的额外复杂性和需求。
  • 在巨型应用程序中,它使得代码更难驾驭和是什么,因为东西发身在别的岗位,你不能平昔看看,并且它们还只怕从根本上海电影制片厂响你尝试阅读的部分代码。
    除此以外还有1部分阅读代码的其实的紧Baba,比如尝试找出ITenantStore
    接口实际上的正经兑现。那对于这3个对代码库或新的依赖注入新手的起码开发人士和开发职员越发相关。
  • 你须求密切思量是还是不是以及哪些将凭借注入引进一个不是以反转控制营造的遗留应用程序。借使借助注入在系统中推进特定样式的道岔和解耦,假若你尝试适应现有应用程序,越发是从未经验的团队,大概会带动挑衅。
  • 依赖注入在反效果的面向对象编制程序是不重要的。当可测试性,故障恢复生机和并行性是生死攸关供给时,功用编制程序正变成更广大的方式。
  • 类型注册和分析会造成运维时惩罚:对于解析是可怜人微权轻的,可是越多的是对于注册。可是,注册只应产生3次。

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
”。依照马克Seeman,使用重视注入“对你的营生来说恐怕是危险的,因为它可能增添你对卓越的API设计的总体知识。1旦你读书了哪些方便的松散耦合的代码大概会发现,你将只好拒绝多量的干活机遇,因为您将不得不与严酷耦合的遗留应用程序。”

在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.

在本章中,您曾经通晓了借助注入与形式(如工厂形式和劳动定位器情势)之间的分化,通过行使推模型,在那之中部分别样类或机件负责实例化重视关系并将它们注入到指标的构造函数中,
属性或方法。这么些其余类或机件未来承受通过营造完全的目的图来构成应用程序,在有的处境下还负责管理创制对象的生命周期。在下一章中,你讲看到您能够采取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

相关文章