SCSF 系列:Smart Client Software Factory 与 ObjectBuilder
【FLYabroad】ObjectBuilder 簡介,SCSF 對 ObjectBuilder 的使用和擴展,SCSF 與控制反轉(IOC)。
上一篇:Smart Client Software Factory 啟動過程詳解 介紹了 SCSF 的啟動過程,啟動的核心工作就是通過 ObjectBuilder 組件準備整個職能客戶端運行環境,因此第一步就是建立一個 Microsoft.Practices.ObjectBuilder.Builder ,SCSF 的整個依賴注入(DI)就基于 ObjectBuilder 。
Object Builder 原先是微軟P&P團隊為 CAB(Composite UI Application Block,是 SCSF 的核心部分,本系列的大部分文章都是介紹 CAB 的) 建立的,后來幾乎在所有P&P項目中使用,包括 Enterprise Libaray ,Web Client Software Factory,WebService Software Factory 等。本文說的 Object Builder 是 ObjectBuilder 1【FLYabroad注】,P&P 開發的 IOC 容器 Unity 是基于 ObjectBuilder 2 的(對 ObjectBuilder 1 進行了改進和加強) 。
通過名字我們大概可以看出 ObjectBuilder 是用來創建對象的,就像一個對象工廠,而這個工廠幾乎可以制造任何對象,并且除了創建對象外還負責對象的生命周期管理(例如合適銷毀,如何銷毀等)。
為什么需要 ObjectBuilder ?原因說來也簡單,一個對象要使用首先需要被創建(并初始化),傳統的通過 new 方式來構造對象的方式是程序強耦合的罪魁:
- 首先 new 是具體化的,我們必須在程序中硬編碼要 new 的對象,而面向對象的最佳實踐是面向抽象;
- 其次,要 new 一個對象,new 的一方必須要引入被 new 一方的程序集依賴和命名空間,這就是強耦合;例如我們要構造 Builder 對象,必須先引入 ObjectBuilder.dll 程序集,同時 using Microsoft.Practices.ObjectBuilder.Builder ;
- 再次,我們所說的多態,如果只通過 new 來構造對象,有時多態的能力就會大打折扣;
要想構造松散耦合的系統,抽象對象構造過程是必須的。這一點在 IOC 模式中可以明顯的體現出來,IOC 容器為我們提供了對象生命周期管理(從創建到銷毀)的場所,它允許我們把對象構造的過程集中在容器中,可以通過配置或者元數據發現(Attribute)等方式動態的構造對象,并且容器提供強大的靈活性來適應對象的生命周期管理功能。這樣對于我們構建松散耦合的系統,構造插件式系統簡直太有用了。
如果希望程序能夠動態的、抽象的構造對象就需要類似 ObjectBuilder 這樣的組件或者服務(Sping 中的 ObjectFactory 也是完成這種工作的)。ObjectBuilder 是一個比較底層的對象創建組件,是 IOC 容器的基礎。ObjectBuilder 就是為了簡化和標準化這些工作的。
對于一般程序員來說我們直接使用 ObjectBuilder 的機會不多,同時網上也有很多不錯的介紹 ObjectBuilder 的文章,這里我們不去過多的關注 OB 的工作原理和流程,而是系統通過 OB 在 SCSF 中的使用,更加透徹的理解上一篇我們講的 SCSF 的工作原理。
一、 ObjectBuilder 的邏輯架構
ObjectBuilder 的核心概念由 4 個組件組成,BuilderContext(IBuilderContext) 是一個包含若干 Strategies (IBuilderStrategy)、Polices(IBuilderPolicy)、Locator(IReadableLocator,IReadWriteLocator)。
BuilderContext 維護了一個策略鏈(strategy chain),對象在經過策略鏈里的所有策略構造后才最終被創建;
Strategy 負責對象創建的一個方面,這些方面主要包括:Pre-Creation Strategy(對象被創建前),Creation Strategy(對象創建),Initialization Strategy (對象初始化),Post-Initialization Strategy (對象初始化完成后)。每個方面中又會有一或多個具體的策略類。例如 SingletonStrategy (屬于 Pre-Creation Strategy)策略用于告訴 ObjectBuilder 應該創建單例對象。具體的 Strategy 通過 object BuildUp(IBuilderContext context, Type typeToBuild, object existing, string idToBuild) 構造對象,通過 object TearDown(IBuilderContext context, object item) 銷毀對象。
Policy 的作用主要是告訴 Strategy 對不同的對象進行構建可能要進行不同操作 。Policy 與 Strategy 通常成對出現,例如 ISingletonPolicy 是配合 SingletonStrategy 在 CreationStrategy 中用的,只有那些被指明了 IsSingleton == true 屬性的對象才使用 SingletonStrategy? 。也就是 Policy 具體規定了對應 Strategy 的執行場合。
Locator 對象定位器,基本上是一個鍵值對的容器,分為 ReadOnlyLocator 和 ReadWriteLocator ,我們可以從 ReadOnlyLocator 獲取對象,可以向 ReadWriteLocator? 中添加、刪除對象,當然也可以獲取對象。
ILifetimeContainer 是一個生命周期容器,ObjectBuilder 通過 ILifetimeContainer 跟蹤對象的生命周期,ILifetimeContainer 最主要的是實現了 IDisposable ,當 Container disposed 的時候,整個容器中的對象都將 disposed。
二、 SCSF 中主要的 Strategy 和 Policy
上一篇 中就介紹過 CreaterBuilder()方法注冊了四個策略: EventBrokerStrategy,CommandStrategy,RootWorkItemInitializationStrategy ,ObjectBuiltNotificationStrategy 和三個缺省 Policy :SingletonPolicy,BuilderTraceSourcePolicy,ObjectBuiltNotificationPolicy 。
class CabApplication<TWorkItem> 中 Run() 最開始要做的就是為整個 SCSF 準備 Builder :
?2?{
?3?????Builder?builder?=?new?Builder();?
?4?????builder.Strategies.AddNew<EventBrokerStrategy>(BuilderStage.Initialization);
?5?????builder.Strategies.AddNew<CommandStrategy>(BuilderStage.Initialization);
?6?????builder.Strategies.Add(new?RootWorkItemInitializationStrategy(this.OnRootWorkItemInitialized),?BuilderStage.Initialization);
?7?????builder.Strategies.AddNew<ObjectBuiltNotificationStrategy>(BuilderStage.PostInitialization);?
?8?
?9?builder.Policies.SetDefault<ISingletonPolicy>(new?SingletonPolicy(true));
10?????builder.Policies.SetDefault<IBuilderTracePolicy>(new?BuilderTraceSourcePolicy(new?TraceSource("Microsoft.Practices.ObjectBuilder")));
11?????builder.Policies.SetDefault<ObjectBuiltNotificationPolicy>(new?ObjectBuiltNotificationPolicy());?
12?
13?????return?builder;
14?}?
這四個策略(Strategy)都是由 SCSF(CAB) 提供的(也就是 CAB 擴展了 ObjectBuilder),三個 Policy 中 ObjectBuiltNotificationPolicy 是 CAB 提供的。下面我們重點介紹 SCSF 提供的這些 BuilderStrategies ,對應的源代碼在 Microsoft.Practices.CompositeUI.BuilderStrategies 命名空間下。
1. EventBrokerStrategy
EventBrokerStrategy 應用于初始化階段(BuilderStage.Initialization),是我們理解 SCSF EventBroker (EventPublicationAttribute 和 EventSubscriptionAttribute)的關鍵。
?2?public?override?object?BuildUp(IBuilderContext?context,?Type?t,?object?existing,?string?id)
?3?{
?4?????WorkItem?workItem?=?GetWorkItem(context,?existing);?
?5?
?6?????if?(workItem?!=?null)
?7?????????EventInspector.Register(existing,?workItem);?
?8?
?9?????return?base.BuildUp(context,?t,?existing,?id);
10?}?
EventBrokerStrategy 告訴 ObjectBuilder 在構建過程中調用 EventInspector.Register(existing, workItem);(在銷毀過程中執行相反操作 EventInspector.Unregister(item, workItem)),EventInspector.Register(existing, workItem) 中執行兩個操作:
1?ProcessPublishers(item,?item.GetType(),?workItem,?true);?//class?EventInspector2?ProcessSubscribers(item,?item.GetType(),?workItem,?true);?//class?EventInspector
ProcessPublishers 檢查 item 中的 Event 上是否標有 EventPublicationAttribute 屬性,如果有就注冊到 EventTopic 的 Publication 中去:
1?topic.AddPublication(item,?info.Name,?workItem,?attr.Scope);?//class?EventInspector?ProcessSubscribers 檢查相應的 item 中的成員上是否有 EventSubscriptionAttribute 屬性,如果有就把它注冊到對應得 Subscription 中去:
【FLYabroad】也就是說,SCSF 啟動過程中,ObjectBuilder 會到被創建的對象上去找標有 EventPublicationAttribute 和 EventSubscriptionAttribute 的事件和方法,并通過 topic, 和 PublicationScope 把對應的事件發布和接受者動態的關聯起來,放到 WorkItem 的 EventTopic 集合中。
2. CommandStrategy
CommandStrategy 與 EventBrokerStrategy 類似,主要負責查看構建的 item 的方法上是否有 CommandHandlerAttribute ,如果有就通過 Delegate 機制構建該對象并添加到當前 workItem 的 Commands 集合中。
3. RootWorkItemInitializationStrategy?
RootWorkItemInitializationStrategy 在 BuilderStage.Initialization 階段調用,并且將 RootWorkItemInitializationCallback 綁定到了 CabApplication 的 OnRootWorkItemInitialized 方法:
1?//CabApplicatioin?類中的?CreatBuilder?方法中2?builder.Strategies.Add(new?RootWorkItemInitializationStrategy(this.OnRootWorkItemInitialized),?BuilderStage.Initialization);
3?
整個 SCSF 應用有且只有一個 RootWorkItem ,ObjectBuilder 在創建 RootWorkItem 時通過調用 OnRootWorkItemInitialized 方法,CabApplication 中默認的 OnRootWorkItemInitialized 方法是一個空方法,子類 CabShellApplication 中重寫了該方法,主要功能是將主窗體 TShell 加入到 RootWorkItem 中:
1?//CabShellApplication?類重寫了父類?CabApplication?空的?OnRootWorkItemInitialized?方法2?protected?sealed?override?void?OnRootWorkItemInitialized()
3?{
4?????BeforeShellCreated();
5?????shell?=?RootWorkItem.Items.AddNew<TShell>();?//將主窗口注冊到?RootWorkItem?中
6?????AfterShellCreated();
7?}?
8?
【FLYabroad】RootWorkItemInitializationStrategy 在構建 RootWorkItem 的過程中被使用,主要任務是將主窗口 TShell 注冊到 RootWorkItem 中。
4. ObjectBuiltNotificationStrategy
ObjectBuiltNotificationStrategy 處理初始化完成后的事情(BuilderStage.PostInitialization),主要作用是在對象創建完成后通知相應的 workItem:
ObjectBuilder 在構造 RootWorkItem 對象過程中會調用 ObjectBuiltNotificationStrategy 的 BuildUp 方法,ObjectBuiltNotificationStrategy 又會調用 ObjectBuiltNotificationPolicy(在CreateBuilder()中注冊)的 policy.AddedDelegates.TryGetValue(workItem, out notification) 獲取 notification 代理(ObjectBuiltNotificationPolicy.ItemNotification? 類型)并執行:
?1?//ObjectBuiltNotificationStrategy?類中的?BuildUp?方法?2?public?override?object?BuildUp(IBuilderContext?context,?Type?typeToBuild,?object?existing,?string?idToBuild)
?3?{
?4?????WorkItem?workItem?=?context.Locator.Get<WorkItem>(new?DependencyResolutionLocatorKey(typeof(WorkItem),?null));
?5?????ObjectBuiltNotificationPolicy.ItemNotification?notification;?
?6?
?7?????if?(policy?==?null)
?8?????????policy?=?context.Policies.Get<ObjectBuiltNotificationPolicy>(null,?null);?
?9?
10?????if?(workItem?!=?null?&&?!Object.ReferenceEquals(workItem,?existing)?&&?policy.AddedDelegates.TryGetValue(workItem,?out?notification))
11?????????notification(existing);?
12?
13?????return?base.BuildUp(context,?typeToBuild,?existing,?idToBuild);
14?}?
15?
ObjectBuiltNotificationStrategy 的 AddedDelegates 是在 WorkItem 初始化時賦值的(在InitializeFields()中注冊 OnObjectAdded):
?1?//WorkItem?的?InitializeFields()?方法中??2?……………………?
?3?ObjectBuiltNotificationPolicy?policy?=?builder.Policies.Get<ObjectBuiltNotificationPolicy>(null,?null);?
?4?
?5?if?(policy?!=?null)
?6?{
?7?????policy.AddedDelegates[this]?=?new?ObjectBuiltNotificationPolicy.ItemNotification(OnObjectAdded);
?8?????policy.RemovedDelegates[this]?=?new?ObjectBuiltNotificationPolicy.ItemNotification(OnObjectRemoved);
?9?}?
10?……………………………
11?
WorkItem 中的 internal event EventHandler> ObjectAdded;是在 ManagedObjectCollection 中注冊:
?1?//ManagedObjectCollection?的構造函數?2?public?ManagedObjectCollection(ILifetimeContainer?container,?IReadWriteLocator?locator,
?3?????????????IBuilder<BuilderStage>?builder,?SearchMode?searchMode,?IndexerCreationDelegate?indexerCreationDelegate,
?4?????????????Predicate<TItem>?filter,?ManagedObjectCollection<TItem>?parentCollection)
?5?????????{
?6?????????????this.container?=?container;
?7?????????????this.locator?=?locator;
?8?????????????this.builder?=?builder;
?9?????????????this.searchMode?=?searchMode;
10?????????????this.indexerCreationDelegate?=?indexerCreationDelegate;
11?????????????this.filter?=?filter;
12?????????????this.parentCollection?=?parentCollection;
13?????????????this.workItem?=?locator.Get<WorkItem>(new?DependencyResolutionLocatorKey(typeof(WorkItem),?null));
14?
15?????????????if?(this.workItem?!=?null)
16?????????????{
17?????????????????this.workItem.ObjectAdded?+=?new?EventHandler<DataEventArgs<object>>(WorkItem_ItemAdded);
18?????????????????this.workItem.ObjectRemoved?+=?new?EventHandler<DataEventArgs<object>>(WorkItem_ItemRemoved);
19?????????????}
20?????????}
WorkItem 的 ObjectAdded 是 internal 的,只能在 CompositeUI.dll 內部使用,ManagedObjectCollection? 將 WorkItem_ItemAdded() 方法綁定到了 WorkItem 的 ObjectAdded 事件,而 WorkItem_ItemAdded 方法又會觸發 ManagedObjectCollection 的 Added 事件(public event EventHandler<DataEventArgs<TItem>> Added), SCSF 中 Added 事件默認沒有注冊,我們可以根據需要通過 ManagedObjectCollection 的 Added 事件處理對象構建完成后的事情。這又是 SCSF 的一個擴展點。
【FLYabroad】ObjectBuiltNotificationStrategy? 結合 ObjectBuiltNotificationPolicy 允許我們通過在 ManagedObjectCollection 上注冊 Added 事件來在對象構建完成后進行擴展處理。
三、SCSF 與控制反轉(IOC\DI)
ObjectBuilder is a framework for creating dependency injection systems,SCSF 中使用 ObjectBuilder 來處理依賴注入。依賴注入的一般原理是,用一個容器來管理對象的生命周期,包需要的括創建、初始化、銷毀,應用程序可以通過名字或者類型從容器中請求到需要的對象。
依賴注入常見的有三種:構造器注入、屬性注入、方法注入。ObjectBuilder 通過 ConstructorReflectionStrategy, PropertyReflectionStrategy, MethodReflectionStrategy 三個策略來對應這三種注入方式。
ObjectBuilder 通過 Attribute 來判斷具體進行哪種注入的,這些屬性包括: [InjectionConstructor] ,[Dependency] ,[CreateNew] ,[MethodInjection] 。同時 SCSF 添加了自己的 Attribute :[ServiceDependency] , [ComponentDependency("id")],[TraceSource]。
SCSF 內部只使用了 [InjectionConstructor],[CreateNew],[ServiceDependency],[ComponentDependency("id")]和[TraceSource]。例如,GlobalBank.BasicAccounts.Module.PurchaseCDViewPresenter 的構造函數:
?1?????????[InjectionConstructor]?2?????????public?PurchaseCDViewPresenter
?3?????????????(
?4?????????????[ComponentDependency("QueueEntry")]?QueueEntry?queueEntry,
?5?????????????[ServiceDependency]?IQuoteService?quoteService,
?6?????????????[ServiceDependency]?ICustomerAccountService?customerAccountsService,
?7?????????????[ServiceDependency]?IAccountService?accountService
?8?????????????)
?9?????????{
10?????????????_queueEntry?=?queueEntry;
11?????????????_quoteService?=?quoteService;
12?????????????_customerAccountsService?=?customerAccountsService;
13?????????????_accountService?=?accountService;
14?????????}
[InjectionConstructor] 用于告訴 ObjectBuilder 使用該構造方法創建該對象(因為一個類可能有多個構造函數)。下一步 ObjectBuilder 要為該構造函數準備參數(如果構造函數有參數的話),ObjectBuilder 同樣還是根據參數前的 Attribute 來判斷如何構建這些參數:
如果是 [CreateNew],則 ObjectBuilder 用相似的規則創建一個新的對象并傳遞給構造器;
如果是 [Dependency] ,OB 會在自己的對象容器中查找符合條件的已創建的對象;
如果是 [ServiceDependency],表示該參數依賴于一個已注冊到 workItem 中的 service ,需要到 workItem 中去查找;
如果是 [ComponentDependency("id")],表示要到父 workItem 中找已經注冊為“id”的對象;例如上例中 [ComponentDependency("QueueEntry")] QueueEntry queueEntry 的 queueEntry 就對應在 GlobalBank.BranchSystems.Module.CustomerWorkItemController 類的 Run() 方法中注冊的 QueueEntry 實例:WorkItem.Items.Add(queueEntry, "QueueEntry");
[TraceSource] 表示依賴于跟蹤源,SCSF 內部的 ClassNameTraceSourceAttribute 就是將類的全名作為一個跟蹤源,我們平時使用的會比較少。
理解 SCSF 依賴注入的另一個要點是 SCSF 在 Microsoft.Practices.CompositeUI.Collections 提供的兩個 Collections:
public?class?ManagedObjectCollection?:?ICollection,?IEnumerable>?public?class?ServiceCollection?:?ICollection,?IEnumerable>?
它們在 WorkItem 類的 InitializeCollectionFacades() 方法中創建并初始化:
?1?????????private?void?InitializeCollectionFacades()?2?????????{
?3?????????????if?(serviceCollection?==?null)
?4?????????????{
?5?????????????????serviceCollection?=?new?ServiceCollection(lifetime,?locator,?builder,
?6?????????????????????parent?==?null???null?:?parent.serviceCollection);
?7?????????????}
?8?
?9?????????????if?(commandCollection?==?null)
10?????????????{
11?????????????????commandCollection?=?new?ManagedObjectCollection<Command>(lifetime,?locator,?builder,
12?????????????????????SearchMode.Up,?CreateCommand,?null,?parent?==?null???null?:?parent.commandCollection);
13?????????????}
14?
15?????????????if?(workItemCollection?==?null)
16?????????????{
17?????????????????workItemCollection?=?new?ManagedObjectCollection<WorkItem>(lifetime,?locator,?builder,
18?????????????????????SearchMode.Local,?null,?null,?parent?==?null???null?:?parent.workItemCollection);
19?????????????}
20?
21?????????????if?(workspaceCollection?==?null)
22?????????????{
23?????????????????workspaceCollection?=?new?ManagedObjectCollection<IWorkspace>(lifetime,?locator,?builder,
24?????????????????????SearchMode.Up,?null,?null,?parent?==?null???null?:?parent.workspaceCollection);
25?????????????}
26?
27?????????????if?(itemsCollection?==?null)
28?????????????{
29?????????????????itemsCollection?=?new?ManagedObjectCollection<object>(lifetime,?locator,?builder,
30?????????????????????SearchMode.Local,?null,?null,?parent?==?null???null?:?parent.itemsCollection);
31?????????????}
32?
33?????????????if?(smartPartCollection?==?null)
34?????????????{
35?????????????????smartPartCollection?=?new?ManagedObjectCollection<object>(lifetime,?locator,?builder,
36?????????????????????SearchMode.Local,?null,?delegate(object?obj)
37?????????????????????????{
38?????????????????????????????return?obj.GetType().GetCustomAttributes(typeof(SmartPartAttribute),?true).Length?>?0;
39?????????????????????????},
40?????????????????????parent?==?null???null?:?parent.smartPartCollection);
41?????????????}
42?
43?????????????if?(eventTopicCollection?==?null)
44?????????????{
45?????????????????if?(parent?==?null)
46?????????????????????eventTopicCollection?=?new?ManagedObjectCollection<EventTopic>(lifetime,?locator,?builder,
47?????????????????????????SearchMode.Local,?CreateEventTopic,?null,?null);
48?????????????????else
49?????????????????????eventTopicCollection?=?RootWorkItem.eventTopicCollection;
50?????????????}
51?
52?????????????if?(uiExtensionSiteCollection?==?null)
53?????????????{
54?????????????????if?(parent?==?null)
55?????????????????????uiExtensionSiteCollection?=?new?UIExtensionSiteCollection(this);
56?????????????????else
57?????????????????????uiExtensionSiteCollection?=?new?UIExtensionSiteCollection(parent.uiExtensionSiteCollection);
58?????????????}
59?????????}
ObjectBuilder (我們在使用 SCSF 時也是這樣)一般是使用這些 Collections 的 Add、AddNew 方法將對象添加到集合中,通過 Get、FindByType
獲得已經注冊的對象,通過 Remove 從集合中刪除對象。將在 WorkItem 中對這些 Collections 進行進一步介紹。
轉載于:https://www.cnblogs.com/flyabroad/archive/2008/06/17/1223741.html
總結
以上是生活随笔為你收集整理的SCSF 系列:Smart Client Software Factory 与 ObjectBuilder的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: XML DTD用法【转载】
- 下一篇: 终于有人把数据、信息、知识讲明白了