Inside ObjectBuilder Part 2_happmaoo的博客-程序员宅基地

技术标签: UI  Access  Microsoft  Security  

<iframe align="top" marginwidth="0" marginheight="0" src="http://www.zealware.com/46860.html" frameborder="0" width="468" scrolling="no" height="60"></iframe>

Object Builder Application Block
/ 黃忠成
2006/9/21

三、 ObjectBuilder Application Block
ObjectBuilde r 一開始 出現於 Microsoft 所提出的 Composite UI Application Block ,主司物件的建立及釋放工作,她實現了本文前面所提及的 Dependency Injection 概念,同時在架構上提供了高度的延展性。運用 ObjectBuilder 來建立物件,設計師可以透過程式或組態檔,對物件建立與釋放的流程進行細部的調整,例如改變物件建立時所呼叫的 Constructor( 建構子 ) ,調整傳入的參數,於物件建立後呼叫特定函式等等。鑑於 ObjectBuilder 的功能逐漸完整,加上社群對於 Dependency Injection 實作體的強烈需求, Microsoft 正式將 ObjectBuilder 納入 Enterprise Library 2006 中,並修改 Caching Logger Security Data Access Application Block 的底層,令其於 ObjectBuilder 整合,以此增加這些 Application Block 的延展性。就官方文件的說明, ObjectBuilder Application Block 提供以下的功能。
1
l 允許要求一個抽象物件或介面,ObjectBuilder會依據程式或組態檔的設定,傳回一個實體物件。
l 回傳一個既存物件,或是每次回傳一個新的物件(多半用於Dependency、Singleton情況,稍後會有詳細說明)。
l 透過特定的Factory建立一個物件,這個Factory可以依據組態檔的設定來建立物件(CustomFactory,隸屬於Enterprise Common Library)。
l 當物件擁有一個以上的建構子時,依據已有的參數,自動選取相容的建構子來建立要求的物件。(Consturctor Injection)
l 允許物件於建立後,透過程式或組態檔來賦值至屬性,或是呼叫特定的函式。(Setter Injection、Interface Injection)
l 提供一組Attribute,讓設計師可以指定需要Injection的屬性,亦或是於物件建立後需要呼叫的函式,也就是使用Reflection來自動完成Injection動作。
l 提供IBuilerAware介面,實作此介面的物件,ObjectBuilder會於建立該物件後,呼叫OnBuildUp或是OnTearDown函式。
l 提供TearDown機制,按建立物件的流程,反向釋放物件。
對於多數讀者來說,這些官方說明相當的隱誨,本文嘗試由架構角度切入,討論 ObjectBuidler 的主要核心概念,再透過實作讓讀者們了解,該如何使用 ObjectBuidler
3-1 The Architecture of Object Builder
圖2
2 ObjectBuilder 中四個主要核心物件的示意圖, BuidlerContext 是一個概念型的環境物件,在這個物件中,包含著一組 Strategys 物件,一組 Polices 物件,一個 Locato r 物件, ObjectBuidler採用Strategys Pipeline(策略流)概念,設計師必須透過Strategy串列來建立物件,而Strategy會透過Polices來尋找『型別/id』對應的Policy物件,使用她來協助建立指定的物件。此處有一個必須特別提出來討論的概念,Strategy在架構上是與型別無關的,每個BuidlerContext會擁有一群Strategys物件,我們透過這個Strategys物件來建立任何型別的物件,不管建立的物件型別為何,都會通過這個Strategys Pipeline。這意味著,當我們希望於建立A型別物件後呼叫函式A1,於建立B型別物件後呼叫函式B1時,負責呼叫函式的Strategy物件會需要一個機制來判別該呼叫那個函式,那就是Policy物件,BuilderContext中擁有一個Polices物件,其中存放著與『型別/id』對應的Policy物件,如圖3所示。
圖3
值得一提的是, Policy 是以 Type/id 方式,也就是『型別 /id 』方式來存放,這種做法不只可以讓不同型別擁有各自的 Policy ,也允許同型別但不同 id 擁有各自的 Policy ObjectBuilder 中的最後一個元素是 Locator Locator 物件在 ObjectBuidler 中扮演著前述的 Service Locator 角色 ,設計師可以用Key/Value的方式,將物件推入Locator中,稍後再以Key值來取出使用。
3-2 、Strategys
ObjectBuilder 內建了許多Strategy,這些Strategy可以大略分成四種類型,如圖4。
圖4
Pre-Creation Strategy
Pre-Creation 意指物件被建立前的初始動作,參與此階段的 Strategy 有: TypeMappingStrategy PropertyReflectionStrategy ConstructorReflectionStrategy MethodReflectionStrategy SingletonStrategy ,稍後我們會一一檢視她們。
Creation Strategy
Creation 類型的 Strategy 主要工作在於建立物件,她會利用 Pre-Creation Strategys 所準備的參數來建立物件, ObjectBuilder 就是運用 Pre-Creation ConstructorReflectionStrategy CreationStrategy 來完成 Constructor Injection 動作。
Initialization Strategy
當物件建立後,會進入初始化階段,這就是 Initialization Strategy 階段,在此階段中, PropertySetterStrategy 會與 PropertyReflectionStrategy 合作,完成 Setter Injectio n 。而MethodExecutionStrategy則會與MethodReflectionStrategy合作,在物件建立後,呼叫特定的函式,也就是Method Injection(視使用方式,Interface Injection是以此種方式完成的)。
Post-Initialization Strategy
在物件建立並完成初始化動作後,就進入了 Post-Initialization Strateg y 階段,在此階段中,BuilderAwareStrategy會探詢已建立的物件是否實作了IBuilderAware介面,是的話就呼叫IBuilderAware.OnBuildUp函式。
關於物件釋放
先前曾經提過,ObjectBuidler在建立物件時,會一一呼叫所有Strategy來建立物件,同樣的!當釋放物件時,ObjectBuilder也會進行同樣的動作,不過方向是相反的,在內建的Strategy中,只有BuilderAwareStrategy會參與物件釋放的動作,在物件釋放時,BuilderAwareStrategy會探詢欲釋放的物件是否實作了IBuidlerAware介面,是的話就呼叫IBuidlerAware.OnTearDown函式。
3-3 A Simple Application
再怎麼詳細的說明,少了一個實例就很難讓人理解,本節以一個簡單的 ObjectBuidler 應用實例開始,一步步帶領讀者進入 ObjectBuilder 的世界。
程式 10
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.ObjectBuilder;
namespace SimpleApp
{
class Program
{
static void Main(string[] args)
{
Builder builder = new Builder();
TestObject obj = builder.BuildUpTestObject>( new Locator(), null, null);
obj.SayHello();
Console.ReadLine();
}
}
public class TestObject
{
public void SayHello()
{
Console.WriteLine("TEST");
}
}
}
這是一個相當陽春的例子,在程式一開始時建立了一個 Builder 物件,她是 ObjectBuilder 所提供的 Facade 物件,其會預先建立一般常用的 Strategy 串列,並於 BuilderUp 函式被呼叫時,建立一個 BuilderContext 物件,並將 Srategy 串列及 Polices 串列指定給該 BuilderContext ,然後進行物件的建立工作。
How Object Creating
要了解前面的例子中, TestObject 物件究竟是如何被建立起來的,首先必須深入 Builder 物件的建構動作。
private StrategyList<tstageenum> strategies = <span style="COLOR: blue">new</span> <span style="COLOR: teal">StrategyList</span><tstageenum>();</tstageenum></tstageenum>
public BuilderBase()
{
}
public PolicyList Policies
{
get { return policies; }
}
public StrategyList<tstageenum> Strategies</tstageenum>
{
get { return strategies; }
}
public Builder(IBuilderConfiguratorBuilderStage> configurator)
{
Strategies.AddNewTypeMappingStrategy>( BuilderStage.PreCreation);
Strategies.AddNewSingletonStrategy>( BuilderStage.PreCreation);
Strategies.AddNewConstructorReflectionStrategy>( BuilderStage.PreCreation);
Strategies.AddNewPropertyReflectionStrategy>( BuilderStage.PreCreation);
Strategies.AddNewMethodReflectionStrategy>( BuilderStage.PreCreation);
Strategies.AddNewCreationStrategy>( BuilderStage.Creation);
Strategies.AddNewPropertySetterStrategy>( BuilderStage.Initialization);
Strategies.AddNewMethodExecutionStrategy>( BuilderStage.Initialization);
Strategies.AddNewBuilderAwareStrategy>( BuilderStage.PostInitialization);
Policies.SetDefaultICreationPolicy>( new DefaultCreationPolicy());
if (configurator != null)
configurator.ApplyConfiguration(this);
}
Buidler 物件被建立時,其建構子會將前面所提及的幾個 Strategys 加到 Strategies 這個 StrategyList Collection 物件中,待 BuildUp 函式被呼叫時指定給新建立的 BuilderContext 物件。
public TTypeToBuild BuildUp<ttypetobuild>(<span style="COLOR: teal">IReadWriteLocator</span> locator,</ttypetobuild>
string idToBuild, object existing, params PolicyList[] transientPolicies)
{
return (TTypeToBuild)BuildUp(locator, typeof(TTypeToBuild), idToBuild, existing, transientPolicies);
}
public virtual object BuildUp(IReadWriteLocator locator, Type typeToBuild,
string idToBuild, object existing, params PolicyList[] transientPolicies)
{
....................
return DoBuildUp(locator, typeToBuild, idToBuild, existing, transientPolicies);
...................
}
private object DoBuildUp(IReadWriteLocator locator, Type typeToBuild, string idToBuild, object existing,
PolicyList[] transientPolicies)
{
IBuilderStrategyChain chain = strategies.MakeStrategyChain();
..............
IBuilderContext context = MakeContext(chain, locator, transientPolicies);
..........................
object result = chain.Head.BuildUp(context, typeToBuild, existing, idToBuild);
.......................
}
private IBuilderContext MakeContext(IBuilderStrategyChain chain,
IReadWriteLocator locator, params PolicyList[] transientPolicies)
{
.............
return new BuilderContext(chain, locator, policies);
}
Builder 的泛型函式 BuildUp 函式被呼叫後,其會呼叫非泛型的 BuildUp 函式,該函式會呼叫 DoBuildUp 函式,此處會透過 strategies( 先前於 Builder 建構子時初始化的 StrategyList 物件 ) 來取得 Strategys 串列,並指定給稍後由 MakeContext 函式建立的 BuilderContext ,最後呼叫 Strategy 串列中第一個 Strategy BuildUp 函式來進行物件的建立動作。在這一連串的動作中,我們可以釐清幾個容易令人混淆的設計,第一!我們是透過 Strategy 串列,也就是 IBuidlerStrategyChain.Head.BuildUp 來建立物件,這個 Head 屬性就是 Strategy 串列中的第一個 Strategy 。第二! BuilderContext 的作用在於,於呼叫各個 Strategy.BuildUp 函式時,給予她們存取此次建立動作所使用的 Strategys Policies 等物件的機會。
Policy 物件的用途
現在,我們弄清楚了 Strategy 的用途, BuilderContext 的真正涵意,但還有兩個元素尚未釐清,其中之一就是 Policy 物件,前面曾經稍微提過, Strategy 是與型別無關的設計概念,因此為了針對不同型別做個別的處理,我們需要另一個與型別相關的設計,那就是 Policy 物件,要確認這點,必須重返 Builder 的建構子。
public Builder(IBuilderConfiguratorBuilderStage> configurator)
{
..................
Policies.SetDefaultICreationPolicy>( new DefaultCreationPolicy());
.................
}
這裡呼叫了 Policies SetDefault 函式, Policies 是一個 PolicyList 物件,其提供了推入 (Set SetDefault) 及取出 (Get) 函式,允許設計者針對所有『型別 /id 』及特定『型別 /id 』指定對應的 IBuilderPolicy 物件,那這有什麼用呢?這個問題可以由 CreationStrategy 類別中的以下這段程式碼來回答。
public override object BuildUp(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)
{
if (existing != null)
BuildUpExistingObject(context, typeToBuild, existing, idToBuild);
else
existing = BuildUpNewObject(context, typeToBuild, existing, idToBuild);
return base.BuildUp(context, typeToBuild, existing, idToBuild);
}
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.SerializationFormatter)]
private object BuildUpNewObject(IBuilderContext context, Type typeToBuild,
object existing, string idToBuild)
{
ICreationPolicy policy = context.Policies.GetICreationPolicy>(typeToBuild, idToBuild);
.........................
InitializeObject(context, existing, idToBuild, policy);
return existing;
}
private void InitializeObject(IBuilderContext context, object existing, string id, ICreationPolicy policy)
{
................
ConstructorInfo constructor = policy.SelectConstructor(context, type, id);
...................
object[] parms = policy.GetParameters(context, type, id, constructor);
...............
method.Invoke(existing, parms);
}
如你所見, CreationStrategy 於建立物件時,會由 Policies 中取出『型別 /id 』對應的 ICreationPolicy 物件,接著利用她來取得 ConstructorInfo( 建構子函式 ) ,再以 GetParameters 函式來取得建構子所需的參數,最後呼叫此建構子。這段程式碼告訴我們 Policy 的真正用途,就是用來協助 Strategy 於不同『型別 /id 』物件建立時,採取不同的動作,這也就是說, Strategy Policy 通常是成對出現的。
Locator
最後一個尚未釐清的關鍵元素是 Locato r ,我們於呼叫Builder的BuildUp函式時,建立了一個Locator物件並傳入該函式,這是用來做什麼的呢?在ObjectBuilder中,Locator扮演兩種角色,第一個角色是提供一個物件容器供Strategy使用,這點可以透過以下程式了解。
public class SingletonStrategy : BuilderStrategy
{
public override object BuildUp(IBuilderContext context, Type typeToBuild,
object existing, string idToBuild)
{
DependencyResolutionLocatorKey key = new DependencyResolutionLocatorKey(
typeToBuild, idToBuild);
if (context.Locator != null && context.Locator.Contains(key, SearchMode.Local))
{
TraceBuildUp(context, typeToBuild, idToBuild, "");
return context.Locator.Get(key);
}
return base.BuildUp(context, typeToBuild, existing, idToBuild);
}
}
SingletonStrategy 是一個用來維持某一個物件只能有一份實體存在,當此Strategy被喚起時,其會先至Locator尋找目前要求的物件是否已被建立,是的話就取出該物件並傳回。Locator同時也可以作為一個Service Locator,這點可以由以下程式碼來驗證。
locator.Add("Test",new TestObject());
.............
TestObject obj = locator.GetTestObject>( "Test");
當然,這種手法有一個問題,那就是 TestObject 物件是預先建立後放在 Locator 中,這並不是一個好的設計,後面的章節我們會提出將 Service Locator Dependency Injection 整合的手法。
PS: ObjectBuidler Locator 離完善的 Service Locator 還有段距離。
四、 Dependency Injection With ObjectBuilder
ObjectBuilder 支援 Dependency Injection 中定義的三種 Injection 模式,本章將一一介紹如何運用 ObjectBuilder 來實現。
4-1 Constructor Injection
Constructor Injection 的精神在於使用建構子來進行注入動作,本節延用 InputAccept 的例子,程式 11 是改採 ObjectBuilder 進行 Constructor Injection 的例子。
程式 11
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using Microsoft.Practices.ObjectBuilder;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
namespace OB_ConstructorInjectionTest
{
class Program
{
static void UseValueParameter(MyBuilderContext context)
{
ConstructorPolicy creationPolicy = new ConstructorPolicy();
creationPolicy.AddParameter(new ValueParameter(typeof(IDataProcessor),
new PromptDataProcessor()));
context.Policies.SetICreationPolicy>(creationPolicy, typeof(InputAccept), null);
}
static void Main(string[] args)
{
MyBuilderContext context = new MyBuilderContext(new Locator());
context.InnerChain.Add(new CreationStrategy());
UseValueParameter(context);
InputAccept accept = (InputAccept)context.HeadOfChain.BuildUp(context,
typeof (InputAccept), null, null);
accept.Execute();
Console.Read();
}
}
internal class MyBuilderContext : BuilderContext
{
public IReadWriteLocator InnerLocator;
public BuilderStrategyChain InnerChain = new BuilderStrategyChain();
public PolicyList InnerPolicies = new PolicyList();
public LifetimeContainer lifetimeContainer = new LifetimeContainer();
public MyBuilderContext()
: this(new Locator())
{
}
public MyBuilderContext(IReadWriteLocator locator)
{
InnerLocator = locator;
SetLocator(InnerLocator);
StrategyChain = InnerChain;
SetPolicies(InnerPolicies);
if (!Locator.Contains(typeof(ILifetimeContainer)))
Locator.Add(typeof(ILifetimeContainer), lifetimeContainer);
}
}
public class InputAccept
{
private IDataProcessor _dataProcessor;
public void Execute()
{
Console.Write("Please Input some words:");
string input = Console.ReadLine();
input = _dataProcessor.ProcessData(input);
Console.WriteLine(input);
}
public InputAccept(IDataProcessor dataProcessor)
{
_dataProcessor = dataProcessor;
}
}
public interface IDataProcessor
{
string ProcessData(string input);
}
public class DummyDataProcessor : IDataProcessor
{
#region IDataProcessor Members
public string ProcessData(string input)
{
return input;
}
#endregion
}
public class PromptDataProcessor : IDataProcessor
{
#region IDataProcessor Members
public string ProcessData(string input)
{
return "your input is: " + input;
}
#endregion
}
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/happmaoo/article/details/83199539

智能推荐

第4周项目1-建立单链表_mengqiqi 6129的博客-程序员宅基地

/* *Copyright(c) 2016, 烟台大学计算机学院 *All rights reserved. *文件名称:建立单链表.cpp *作 者:孟琪琪 *完成日期:2016年 9月 22日 *问题描述:定义单链表存储结构,用头插法和尾插法建立单链表,并显示建立好以后的结果。 *输入描述:此程序没有输入。 *程序输出

Appium基础学习之 | ANDROID_UIAUTOMATOR定位介绍_雨墨轩痕的博客-程序员宅基地

Appium实现自动化底层是依赖UiAutomator框架,定位元素也是经由UiAutomator处理后转换Accessibility服务对象完成元素查找并且操作。在前面介绍过Appium-Desktop支持的ID、XPATH、ACCESSIBILITY_ID、CLASS_Name定位,对于这四种定位比较容易理解,剩下的ANDROID_UIAUTOMATOR定位在这篇文章介绍。一、疑问..._android_uiautomator

判断设备唯一性_网页判断设备唯一性_林剑南的博客-程序员宅基地

判断设备唯一性 if ((!deviceId.equals("0") && !schoolDeviceId.equals("0"))) { Optional<SchoolDevice> deviceOpt = deviceRepository.findById(Integer.parseInt(schoolDeviceId)); if (!device..._网页判断设备唯一性

Linux服务依赖账户,安装和使用Imapsync将邮件帐户从一个服务器导入到另一个服务器..._考研兔萌酱的博客-程序员宅基地

本文介绍在Debian/Ubuntu/CentOS/RHEL系统下安装Imapsync的方法,并使用Imapsync将邮件帐户从一个服务器导入到另一个服务器。背景我使用Ispconfig提供Web托管服务,很长一段时间里,将现有的Cpanel客户迁移到Ispconfig真的很痛苦,特别是当你需要导入所有用户的邮箱和数据时,我不得不在两台服务器之间手动导入Dovecot邮箱文件夹。这是一个枯燥乏味的..._imapsync

系统学习 Java IO (四)----文件的读写和随机访问 FileInputStream/FileOutputStream & RandomAccessFile..._weixin_30915275的博客-程序员宅基地

目录:系统学习 Java IO---- 目录,概览文件输入流 FileInputStream这是一个简单的FileInputStream示例:InputStream input = new FileInputStream("D:\\input.txt");int data = input.read();while(data != -1) { //do something w...

Dart异步与消息循环机制_weixin_30787531的博客-程序员宅基地

Dart与消息循环机制翻译自https://www.dartlang.org/articles/event-loop/异步任务在Dart中随处可见,例如许多库的方法调用都会返回Future对象来实现异步处理,我们也可以注册Handler来响应一些事件,如:鼠标点击事件,I/O流结束和定时器到期。这篇文章主要介绍了Dart中与异步任务相关的消息循环机制,阅读完这篇文章后相信你可写出更赞的异步执...

随便推点

iOS webView展示部分docx出现乱码解决方案_碌碌无为的小蚂蚁的博客-程序员宅基地

项目中遇到预览docx和pdf要求:在开发过程中webView支持预览pdf和docx,so直接使用webView,但在后期测试阶段发现部分docx预览时为乱码现象,查找方案发现编码utf-8以及GBK等都无法解决乱码问题。后发现如下方案能做修改:content-type 用于定义用户的浏览器或相关设备如何显示将要加载的数据,或者如何处理将要加载的数据,

全景拼接的实现_http://blog.csdn.net/shanghaiqianlun/article/detai_Suki wu的博客-程序员宅基地

根据官方代码行修改后:from pylab import *from numpy import *from PIL import Image# If you have PCV installed, these imports should workfrom PCV.geometry import homography, warpfrom PCV.localdescriptors im..._http://blog.csdn.net/shanghaiqianlun/article/details/12090595

Java对象初始化_java 对象初始化_小虎哥的技术博客的博客-程序员宅基地

Java对象初始化,对象初始化流程: 加载字节码(只加载一次)->初始化字段->父类构造方法->自身构造方法。_java 对象初始化

oracle更改字段类型 有数据无数据的时候,修改字段长度,增加字段_oracle 中modify 有数据和没有数据_嘿;-)翔�的博客-程序员宅基地

有一个表名为tb,字段段名为request_id,数据类型int 更改为VARCHAR2(64)。1、假设字段数据为空,则不管改为什么字段类型,可以直接执行:alter table tb modify (request_id varchar2(64));2、假设字段没有数据,则改为varchar2(20)可以直接执行:alter table tb modify (request_id varchar2(64));3、假设字段有数据,则改为varchar2(40)执行时会弹出:“ORA-0_oracle 中modify 有数据和没有数据

蓝屏代码_weixin_33912246的博客-程序员宅基地

0 0x00000000 作业完成。1 0x00000001 不正确的函数。2 0x00000002 系统找不到指定的档案。3 0x00000003 系统找不到指定的路径。4 0x00000004 系统无法开启档案。5 0x00000005 拒绝存取。6 0x00000006 无效的代码。7 0x00000007 储存体控制区块已毁。8 0x00000008 储存体空间不足,...

网页登录设计(四):登录成功后部分_登录成功页面_贺呗的博客-程序员宅基地

登录成功后,我们就可以进入页面了.如果登录或者注册不晓得的,可以先去看前面几个博客,这里就简单的把数据库注册的数据展示出来,细节什么的,慢慢去添加更改就好了.由于要展示数据库的注册信息,我们要把信息放的表格中展示出来,这里就要用到jsp的东西了,所以先了解一下jsp;<% 代码片段 %> : 在这中间就是填写Java代码的<%= 表达式 %> : 这个是写表达式这里就说这两个,其它的可以自行学习一下:那么我们创建一个.jsp页面来当作列表页面<%@page imp_登录成功页面

推荐文章

热门文章

相关标签