Unity應用架構設計oC工廠理念先行
閱讀目錄
工廠模式初探
工廠的分類
Singleton Factory
Transient Factory
Pool Factory
小結
一談到 『IoC』,有經驗的程式設計師馬上會聯想到控制反轉,將建立物件的責任反轉給工廠。IoC是依賴注入 『DI』 的核心,大名鼎鼎的Spring框架就是一個非常卓越的的控制反轉、依賴注入框架。遺憾的是,我們顯然不能在中去使用Spring框架,但思想是相通的——IoC也好,控制反轉也罷,本質上是一個工廠,或者又被稱為容器,我們可以自己維護一個工廠來實現對物件的管理,這也是本文的核心內容。
工廠模式初探
工廠,顧名思義,就是生產物件的地方。如果之前沒有接觸過設計模式,你可能會疑惑,我直接使用 『new』 關鍵字難道不能建立物件嗎?為什麼還要大費周章的讓工廠來建立?當然這是沒錯的,直接使用 『new』 關鍵字很簡潔,也很易懂,但你考慮過物件的釋放嗎?你可能會說不用考慮啊,GC會幫我們回收啊。
其實問題就出在這裡,因為你沒有考慮物件管理的動機,所以就不會有工廠這個概念。試想一下,使用ADO.NET或者JDBC去訪問資料庫,我們是不是要先建立一個Connection,當工作結束後,Close了這個連線。當再一次需要連線資料庫時,再建立一次Connection,這背後其實有隱患。因為和資料庫建立連線是非常耗時的,只是我們感受不到。我們能不能在關閉連線時,不銷燬物件,而是將其放到一個物件池,當下一次請求來時,直接從物件池中獲取。這就是工廠的動機,對物件的建立和釋放進行管理,這樣可以有效的提高效率。
注:釋放指的是物件實現了IDisposable介面的非託管資源,在uMVVM框架,工廠維護的都是託管資源,銷燬由GC決定
工廠的分類
在uMVVM框架中,我將工廠分為三類:單例(Singleton),臨時(Transient),池(Pool)。
Singleton :該工廠生產的物件是單例的,即一旦生產出來的物件將處理所有的請求,不會因為不同的請求而產生新的物件,通常需要考慮多執行緒併發問題
Transient :該工廠生產的物件是臨時的,轉瞬即逝的,即每一次請求產生一個新物件,處理請求完畢後就被銷燬
Pool:該工廠並不會無限的建立物件,取而代之的是內部維護了一個物件池,當請求來時,從物件池中獲取,當請求處理完畢後,物件也不會被銷燬,而是再次放回物件池中
我們可以為這三種工廠宣告公共的介面:IObjectFactory,這是非常有必要的,方便在執行時根據需求動態的切換不同工廠:
public interface IObjectFactory { object AcquireObject(string className); object AcquireObject(Type type); object AcquireObject() where TInstance : class, new(); void ReleaseObject(object obj); }
這個介面功能很簡單,透過統一的入口對物件進行建立與銷燬的管理。
Singleton Factory
有了統一的工廠的介面之後,接下來就是去實現對應的工廠了,第一個要實現的就是 Singleton Factory:
public class SingletonObjectFactory:IObjectFactory { ////// 共享的字典,不會因為不同的SingletonObjectFactory物件返回不唯一的例項物件 /// private static Dictionary_cachedObjects = null; private static readonly object _lock=new object(); private Dictionary CachedObjects { get { lock (_lock) { if (_cachedObjects==null) { _cachedObjects=new Dictionary (); } return _cachedObjects; } } } //...省略部分程式碼... public object AcquireObject () where TInstance:class,new() { var type = typeof(TInstance); if (CachedObjects.ContainsKey(type)) { return CachedObjects[type]; } lock (_lock) { var instance=new TInstance(); CachedObjects.Add(type, instance); return CachedObjects[type]; } } }
上述程式碼中,我們需要定義一個全域性的字典,用來儲存所有的單例,值得注意的是,CachedObjects 字典是一個 static 型別,這表明這是一個共享的字典,不會因為不同的SingletonObjectFactory物件返回不唯一的例項物件。
還有一點,單例模式最好考慮一下多執行緒併發問題,雖然這是一個 『偽』 需求,畢竟是個單執行緒應用程式,但 uMVVM 框架還是考慮了多執行緒併發的問題,使用 lock 關鍵字,它必須是一個 static 型別,保證 lock 了同一個物件。
Transient Factory
Transient Factory 是最容易實現的工廠,不用考慮多執行緒併發問題,也不用考慮Pool,對每一次請求返回一個不同的物件:
public class TransientObjectFactory : IObjectFactory { //...省略部分程式碼... public object AcquireObject() where TInstance : class, new() { var instance = new TInstance(); return instance; } }
Pool Factory
Pool Factory 相對來說是比較複雜的工廠,它對 Transient Factory 進行了升級——建立例項前先去Pool中看看是否有未被使用的物件,有的話,那麼直接取出返回,如果沒有則向Pool中新增一個。
Pool的實現有兩種形式,一種是內建了諸多物件,還有一種是初始時是一個空的池,然後再往裡面新增物件。第一種效率更高,直接從池裡面拿,而第二種更省記憶體空間,類似於懶載入,uMVVM 的物件池技術使用第二種模式。
public class PoolObjectFactory : IObjectFactory { ////// 封裝的PoolData /// private class PoolData { public bool InUse { get; set; } public object Obj { get; set; } } private readonly List_pool; private readonly int _max; /// /// 如果超過了容器大小,是否限制 /// private readonly bool _limit; public PoolObjectFactory(int max, bool limit) { _max = max; _limit = limit; _pool = new List(); } private PoolData GetPoolData(object obj) { lock (_pool) { for (var i = 0; i /// 獲取物件池中的真正物件 /// /// /// private object GetObject(Type type) { lock (_pool) { if (_pool.Count > 0) { if (_pool[0].Obj.GetType() != type) { throw new Exception(string.Format("the Pool Factory only for Type :{0}", _pool[0].Obj.GetType().Name)); } } for (var i = 0; i = _max && _limit) { throw new Exception("max limit is arrived."); } object obj = Activator.CreateInstance(type, false); var p1 = new PoolData { InUse = true, Obj = obj }; _pool.Add(p1); return obj; } } private void PutObject(object obj) { var p = GetPoolData(obj); if (p != null) { p.InUse = false; } } public object AcquireObject(Type type) { return GetObject(type); } public void ReleaseObject(object obj) { if (_pool.Count > _max) { if (obj is IDisposable) { ((IDisposable)obj).Dispose(); } var p = GetPoolData(obj); lock (_pool) { _pool.Remove(p); } return; } PutObject(obj); } }
上述的程式碼透過建構函式的 max 決定Pool的大小,limit 參數列示超過Pool容量時,是否可以再繼續往Pool中新增資料。方法 GetObject 是最核心的方法,邏輯非常簡單,獲取物件之前先判斷Pool中是否有未被使用的物件,如果有,則返回,如果沒有,則根據 limit 引數再決定是否可以往Pool中新增資料。
小結
工廠模式是最常見的設計模式,根據工廠的型別可以獲取不同形式的資料物件,比如單例資料、臨時資料、亦或是物件池資料。這一章的工廠模式很重要,也是對下一篇物件的注入『Inject』做準備,故稱之為理念先行。
原始碼託管在Github上,點選此瞭解
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2001/viewspace-2800263/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Unity應用架構設計(7)——IoC工廠理念先行Unity應用架構
- Unity應用架構設計(12)——AOP思想的實踐Unity應用架構
- Unity應用架構設計(6)——設計動態資料集合ObservableListUnity應用架構
- Unity應用架構設計(9)——構建統一的 RepositoryUnity應用架構
- Unity應用架構設計(1)—— MVVM 模式的設計和實施(Part 1)Unity應用架構MVVM模式
- Unity應用架構設計(1)—— MVVM 模式的設計和實施(Part 2)Unity應用架構MVVM模式
- Unity應用架構設計(4)——設計可複用的SubView和SubViewModel(Part 1)Unity應用架構View
- Unity應用架構設計(8)——使用ServiceLocator實現物件的注入Unity應用架構物件
- Unity應用架構設計 ViewModel之間實現共享資料Unity應用架構View
- Unity應用架構設計(5)——ViewModel之間如何共享資料Unity應用架構View
- 應用架構圖的設計應用架構
- React應用架構設計指南React應用架構
- SaaS架構:應用服務、應用結構設計架構
- 面向微服務架構設計理念與實踐微服務架構
- 設計模式 | 簡單工廠模式及典型應用設計模式
- iOS應用架構談:架構設計的方法論iOS應用架構
- 使用Lambdas重構工廠設計模式設計模式
- iOS應用架構談(一):架構設計的方法論iOS應用架構
- .NET應用架構設計—重新認識分層架構(現代企業級應用分層架構核心設計要素)應用架構
- React Native App應用架構設計React NativeAPP應用架構
- 論軟體架構設計及應用架構
- 百萬年薪架構師之路:談應用系統架構設計架構
- 總結 - 設計模式,企業應用架構模式,架構模式設計模式應用架構
- Unity應用架構設計(2)——使用中介者模式解耦ViewModel之間通訊Unity應用架構模式解耦View
- 綜合使用抽象工廠、工廠方法的應用抽象
- Opendaylight 中 關於工廠設計模式的應用設計模式
- 工廠設計模式設計模式
- Angular應用架構設計-2:Data Service模式Angular應用架構模式
- 雲邊協同架構助力智慧工廠視覺 AI 缺陷檢測應用構建架構視覺AI
- Unity應用架構設計(10)——繞不開的協程和多執行緒(Part 2)Unity應用架構執行緒
- Unity應用架構設計(10)——繞不開的協程和多執行緒(Part 1)Unity應用架構執行緒
- 設計模式-簡單工廠、工廠方法模式、抽象工廠模式設計模式抽象
- 一文搞懂SaaS應用架構:應用服務、應用結構、應用互動設計應用架構
- 設計模式----工廠設計模式設計模式
- 設計模式-工廠設計模式設計模式
- 設計模式-工廠模式二(工廠方法模式)設計模式
- Angular應用架構設計-5:設計原則與總結Angular應用架構
- Java設計模式之簡單工廠、工廠方法和抽象工廠Java設計模式抽象