MS 的 Net Framework 2.0的Enterprise Library - November 2005 CTP 和Composite User Interface (UI) Application Block都是依赖于一个核心的组件ObjectBuilder。它同时实现了两个重要的设计模式Service Locator 模式和Dependency Injection
模式,是一个IOC容器。ObjectBuilder可以作为一个IOC框架开发,Enterprise Library - November 2005 CTP的各个模块之间的依赖关系相比较他的以前的版本大大减弱。
“依赖注入”(Dependency Injection)设计模式和 “服务定位器”(Service Locator)设计模式的目标:应该将组件的配置与使用分离开。
"依赖注入”
(Dependency Injection)来自IOC容器中,在DotNet底下现在比较著名的就是
Castle和
Spring.net。依赖注入的形式主要有三种,我分别将它们叫做构造子注入(Constructor Injection)、设值方法注入(Setter Injection)和接口注入(Interface Injection)。 ObjectBuilder实现了构造子注入(Constructor Injection)、设值方法注入(Setter Injection)。
“服务定位器”(Service Locator)模式模式背后的基本思想是:有一个对象(即服务定位器)知道如何获得一个应用程序所需的所有服务。
下面是Object Builder的具体介绍:
Object Builder
The ObjectBuilder is a new subsystem that is shared between Enterprise Library and the Composite User Interface (UI) Application Block. Enterprise Library uses the ObjectBuilder subsystem for tasks such as injecting configuration into block classes and connecting instrumentation classes to application blocks.
The Composite UI Application Block uses a custom underlying system called ObjectBuilder to inject instances of objects of the appropriate type and with preset properties into the application at runtime.
Design of ObjectBuilder
The construction and disposal of object instances is a common process in most applications, and particularly in business applications such as those built using the Composite UI Application Block and the Enterprise Library. For this reason, these blocks take advantage of an underlying sub-system called ObjectBuilder that performs all of the repetitive and necessary tasks for creating object instances, while still providing a high level of flexibility.
ObjectBuilder encapsulates features that simplify the creation of object instances. It can:
- Ensure the creation of specific concrete class instances, even when requests are for abstract types.
- Ensure the return of existing object instances when this is appropriate, or always generate new instances.
- Create the appropriate objects from factory classes based on configuration data.
- Intelligently select the appropriate constructor when a class exposes more than one constructor.
- Apply values to public properties automatically, and execute methods on the object, in response to pre-defined policies.
- Respond to attributes declared on the properties and methods, which influence the creation and naming of the new object.
- Communicate automatically with objects that support the IBuilderAware interface to indicate that object creation is complete.
- Provide a tear down facility that can remove settings from existing objects by reversing the chain of operations.
ObjectBuilder is a low-level utility that, in most cases, you will not interact with directly in your applications. The classes in the application blocks use it to generate object instances in response to your code creating the classes declared within the application blocks.
However, you can use the features of ObjectBuilder directly in your applications and your own frameworks if you wish. You can also influence the behavior of ObjectBuilder by creating your own strategies or modifying the existing strategies.
Note:
|
ObjectBuilder is a patterns & practices Application Block, but - due to the highly specific audience that it tackles and its recent inception - is not yet fully documented as a stand-alone asset like Enterprise Library application blocks or the Composite UI Application Block.
|
ObjectBuilder Architecture
ObjectBuilder uses a pipeline of strategies that allows multiple operations to take place as objects are instantiated and prepared for use. This allows you to control the order that the processes take place. It also supports controlled disposal of object instances by executing the appropriate pipeline processes in the reverse order.
ObjectBuilder strategies manage the processes performed on objects during construction and disposal. The ObjectBuilder pipeline is organized into stages, and each stage of the pipeline contains multiple strategies. You can implement your own strategies as a .NET class with a specific interface.
ObjectBuilder Methods
ObjectBuilder resides in the namespace Microsoft.Practices.ObjectBuilder, and the base class BuilderBase exposes two methods. The BuildUp method has two overloads:
[C#]
|
Copy Code
|
BuildUp(locator, type, id, instance, policies[] ); BuildUp<type>(locator, id, instance, policies[] ); |
where:
- locator is a reference to a class that implements the IReadWriteLocator interface, and which provides hints as to the location of the object or class. For more information, see "Using a ReadWriteLocator" later in this topic.
- type is the type of object to create.
- id is the identifier to assign to the new object instance.
- instance is an optional reference to an existing object instance upon which the pipeline process will act. This allows you to take existing objects and ensure that they are properly prepared for use by passing them through the pipeline. ObjectBuilder applies only the appropriate processes to such object instances.
- policies[] is an array of PolicyList instances that implement transient policies that over-ride the built-in policies. For more information, see "Using a PolicyList" later in this topic.
The TearDown method takes an existing object instance and runs it back through the strategy chain. This process can remove features added to the object during the BuildUp process if you want to re-use the object. You do not have to call the TearDown method on objects that you no longer need to use.
The signature of the TearDown method is:
[C#]
|
Copy Code
|
TearDown<type>(instance); |
where:
- type is the type to un-build. If not provided, ObjectBuilder infers this from the type of object passed as the instance parameter.
- instance is a reference to an existing object instance upon which the pipeline process will act in reverse.
Using a ReadWriteLocator
ObjectBuilder uses the concept of a lifetime container to store object references, which ensures the correct management of objects and their disposal at the correct times. Locators reference individual objects within the lifetime container. Multiple locators can point to the same object instance. For example, an object can have separate locators that reference it through the class type-name, the interfaces it implements, and the object name.
Locators can be read-only or read-write, and the BuildUp method of ObjectBuilder takes an instance of an object that implements the IReadWriteLocator interface.
Using a PolicyList
A PolicyList is a set of policies, each represented by classes that implement the ICreationPolicy interface, that together influence the way that an object is created by ObjectBuilder. Policies can be transient or permanent.
Transient policies are those generated automatically by the strategies in ObjectBuilder or through reflection over the attributes on the methods and properties declared in the class file.
Permanent policies are those you create by implementing the ICreationPolicy interface. You can pass an array of these class instances to the BuildUp method in ObjectBuilder.
Pipeline Stages
The pipeline in ObjectBuilder consists of four stages. These are:
- PreCreation, which occurs before ObjectBuilder creates a new instance of the object.
- Creation, which occurs after ObjectBuilder creates the new object instance
- Initialization, which occurs before properties are set on the new object instance
- PostInitialization, which occurs just before return of the newly created object
Table 1 shows the default processes that ObjectBuilder carries out as each stage of the pipeline:
Table 1 – The stages of starting up a Composite UI Application Block application
Pipeline stage
|
ObjectBuilder Strategies
|
PreCreation
|
TypeMappingStrategy
SingletonStrategy
ConstructorReflectionStrategy
|
Creation
|
CreationStrategy
|
Initialization
|
PropertySetterStrategy
PropertyReflectionStrategy
MethodReflectionStrategy
MethodExecutionStrategy
|
PostInitialization
|
BuilderAwareStrategy
|
The application blocks that use ObjectBuilder add specific strategies to the pipeline, and you can add your own strategies if required.
Strategy Types
The default strategies for ObjectBuilder listed in Table 1 are:
- TypeMappingStrategy. This strategy can set the actual return type for objects. For example, a request for an abstract or interface type IMyObject can force automatically translation into the concrete type MyObject.
- SingletonStrategy. This strategy specifies whether ObjectBuilder returns a new instance of an object, or returns an existing instance if one is available.
- ConstructorReflectionStrategy. This strategy inspects the class looking for attributes declared on constructors, in particular the [Constructor] attribute, and choosing which to use to construct the object. More details of how parameters in the constructor decorated with the [Dependency] and [CreateNew] attributes influence behavior occur later in this section.
- CreationStrategy. This is the point where the new object is instantiated, using either the constructor or the Activatorclass methods.
- PropertySetterStrategy. This strategy can set the value of public properties of the new object instance, based on policy.
- PropertyReflectionStrategy. This strategy inspects the class looking for attributes on properties, and applies these to the new object instance. Properties decorated with the [Dependency] and [CreateNew] attributes cause injection of these values into the new object instance.
- MethodReflectionStrategy. This strategy inspects the class looking for attributes on methods that must run during the Initialization stage.
- MethodExecutionStrategy. This strategy executes methods on the new object instance, depending on policy.
- BuilderAwareStrategy. This strategy inspects the class to see if it implements the IBuilderAware interface. If it does, ObjectBuilder informs the object when construction is complete and the object is ready for use by raining the OnBuiltUp event. If ObjectBuilder is executing the TearDown method, it raises the OnTearingDown event.
You can derive your own class from the BuilderBase class if you want to create more stages, modify or remove the existing ones, use your own stages, or pre-initialize a builder to suit your requirements. Looking at the source file for the builder (Builder.cs) provides an example of how this is possible.
Attribute-Based Dependency Injection
ObjectBuilder supports a general-purpose attribute-based dependency injection. Two of the built-in strategies, ConstructorInjectionStrategy and PropertyInjectionStrategy, provide dependency injection. Both of these strategies support a common set of attributes that you can apply to variables:
- [CreateNew] tells the dependency injection system always to create a new one of whatever it is you need. This is helpful for things like MVC or MVP, where creating a view will automatically generate a new controller/presenter.
- [Dependency] is a general-purpose attribute with three optional parameters:
Name
specifies a named object instead of an un-named object. The default if omitted is null (un-named).
The provision of these parameters on the [Dependency] attribute means that it can satisfy all of the following requirements:
- I need the unnamed X (where X is a type). If it does not exist, throw an exception.
- I need the unnamed X. If it does not exist, create a new one.
- I want the unnamed X. If it does not exist, give me null instead.
- I need the X named Y (where Y is a string). If it does not exist, throw an exception.
- I need the X named Y. If it does not exist, create a new one.
- I want the X named Y. If it does not exist, give me null instead.
For example, this code always generates an object of type MyCustomObject:
[C#]
|
Copy Code
|
using Microsoft.Practices.ObjectBuilder; [Dependency(CreateType=typeof(MyCustomObject), NotPresentBehavior=NotPresentBehavior.CreateNew) public ICustomObject MyCustomObject { set { ... } } |
If the system cannot find an ICustomObject, it will create a new MyCustomObject, and register it with the type of ICustomObject for the next person who needs an ICustomObject. The default is null.
Constructor, Property, and Method Injection
Three of the built-in strategies, the ConstructorReflectionStrategy, PropertyReflectionStrategy, and MethodReflectionStrategy, use the [Dependency] and [CreateNew] attributes to control their behavior.
The ConstructorReflectionStrategy has two phases. First, it figures out which constructor to use. Second, it figures out how to satisfy those constructor parameters.
The ConstructorReflectionStrategy first looks for any constructor decorated with the [Constructor] attribute (there can be only one of these) and uses this constructor if found. If there is no decorated constructor, yet there is only one constructor, it will use that constructor. If there are multiple constructors but none carries the [Constructor] attribute, this strategy throws an exception.
After selecting the constructor, the strategy determines how to fulfill the requirements of the parameters to the constructor. These may be marked with the [Dependency] and/or [CreateNew] attributes. Any parameter which is undecorated will be treated as though it had been decorated with the default [Dependency] attribute (un-named, NotPresentBehavior= NotPresentBehavior.CreateNew, SearchMode = Up).
The PropertyReflectionStrategy looks for properties with the [Dependency] and [CreateNew] attributes, and satisfies them appropriately (they must be public and have setters). It does not do anything with any undecorated properties on a class.
The MethodReflectionStrategy looks for methods decorated with [MethodInjection], which execute during the initialization phase. The parameters of these methods may contain the [CreateNew] and [Dependency] attributes. Any undecorated parameter is treated as though it had been decorated with the default [Dependency] attribute (un-named, NotPresentBehavior= NotPresentBehavior.CreateNew, SearchMode = Up).
How the CAB uses ObjectBuilder
There are five more strategies in place by default in the Composite UI Application Block, as shown in the Table 2. These are in addition to the default strategies implemented within ObjectBuilder.
Table 2 – The stages of starting up a Composite UI Application Block application
Pipeline stage
|
Composite UI Application Block Strategies
|
PreCreation
|
TraceSourceStrategy
ConfigurationStrategy
StateStrategy
|
Initialization
|
EventBrokerStrategy
CommandStrategy
|
The strategies listed in Table 2 are:
- TraceSourceStrategy. This strategy automatically adds a TraceSourceListener to the new object to provide tracing capabilities.
- ConfigurationStrategy. This strategy automatically loads any configuration data for the new object, based on the policy settings.
- StateStrategy. This strategy automatically loads any stored state into the new object, based on the policy settings.
- EventBrokerStrategy. This strategy automatically registers or un-registers event inspectors.
- CommandStrategy. This strategy automatically registers or un-registers command handlers for objects.