日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

Unity应用架构设计(7)——IoC工厂理念先行

發(fā)布時(shí)間:2025/7/25 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Unity应用架构设计(7)——IoC工厂理念先行 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一談到 『IoC』,有經(jīng)驗(yàn)的程序員馬上會(huì)聯(lián)想到控制反轉(zhuǎn),將創(chuàng)建對象的責(zé)任反轉(zhuǎn)給工廠。IoC是依賴注入 『DI』 的核心,大名鼎鼎的Spring框架就是一個(gè)非常卓越的的控制反轉(zhuǎn)、依賴注入框架。遺憾的是,我們顯然不能在Unity 3D中去使用Spring框架,但思想是相通的——IoC也好,控制反轉(zhuǎn)也罷,本質(zhì)上是一個(gè)工廠,或者又被稱為容器,我們可以自己維護(hù)一個(gè)工廠來實(shí)現(xiàn)對對象的管理,這也是本文的核心內(nèi)容。

工廠模式初探

工廠,顧名思義,就是生產(chǎn)對象的地方。如果之前沒有接觸過設(shè)計(jì)模式,你可能會(huì)疑惑,我直接使用 『new』 關(guān)鍵字難道不能創(chuàng)建對象嗎?為什么還要大費(fèi)周章的讓工廠來創(chuàng)建?當(dāng)然這是沒錯(cuò)的,直接使用 『new』 關(guān)鍵字很簡潔,也很易懂,但你考慮過對象的釋放嗎?你可能會(huì)說不用考慮啊,GC會(huì)幫我們回收啊。

其實(shí)問題就出在這里,因?yàn)槟銢]有考慮對象管理的動(dòng)機(jī),所以就不會(huì)有工廠這個(gè)概念。試想一下,使用ADO.NET或者JDBC去訪問數(shù)據(jù)庫,我們是不是要先建立一個(gè)Connection,當(dāng)工作結(jié)束后,Close了這個(gè)連接。當(dāng)再一次需要連接數(shù)據(jù)庫時(shí),再建立一次Connection,這背后其實(shí)有隱患。因?yàn)楹蛿?shù)據(jù)庫建立連接是非常耗時(shí)的,只是我們感受不到。我們能不能在關(guān)閉連接時(shí),不銷毀對象,而是將其放到一個(gè)對象池,當(dāng)下一次請求來時(shí),直接從對象池中獲取。這就是工廠的動(dòng)機(jī),對對象的創(chuàng)建和釋放進(jìn)行管理,這樣可以有效的提高效率。

注:釋放指的是對象實(shí)現(xiàn)了IDisposable接口的非托管資源,在uMVVM框架,工廠維護(hù)的都是托管資源,銷毀由GC決定

工廠的分類

在uMVVM框架中,我將工廠分為三類:單例(Singleton),臨時(shí)(Transient),池(Pool)。

  • Singleton :該工廠生產(chǎn)的對象是單例的,即一旦生產(chǎn)出來的對象將處理所有的請求,不會(huì)因?yàn)椴煌恼埱蠖a(chǎn)生新的對象,通常需要考慮多線程并發(fā)問題
  • Transient :該工廠生產(chǎn)的對象是臨時(shí)的,轉(zhuǎn)瞬即逝的,即每一次請求產(chǎn)生一個(gè)新對象,處理請求完畢后就被銷毀
  • Pool:該工廠并不會(huì)無限的創(chuàng)建對象,取而代之的是內(nèi)部維護(hù)了一個(gè)對象池,當(dāng)請求來時(shí),從對象池中獲取,當(dāng)請求處理完畢后,對象也不會(huì)被銷毀,而是再次放回對象池中

我們可以為這三種工廠聲明公共的接口:IObjectFactory,這是非常有必要的,方便在運(yùn)行時(shí)根據(jù)需求動(dòng)態(tài)的切換不同工廠:

public interface IObjectFactory {object AcquireObject(string className);object AcquireObject(Type type);object AcquireObject<TInstance>() where TInstance : class, new();void ReleaseObject(object obj); }

這個(gè)接口功能很簡單,通過統(tǒng)一的入口對對象進(jìn)行創(chuàng)建與銷毀的管理。

Singleton Factory

有了統(tǒng)一的工廠的接口之后,接下來就是去實(shí)現(xiàn)對應(yīng)的工廠了,第一個(gè)要實(shí)現(xiàn)的就是 Singleton Factory:

public class SingletonObjectFactory:IObjectFactory {/// <summary>/// 共享的字典,不會(huì)因?yàn)椴煌腟ingletonObjectFactory對象返回不唯一的實(shí)例對象/// </summary>private static Dictionary<Type,object> _cachedObjects = null;private static readonly object _lock=new object();private Dictionary<Type, object> CachedObjects{get{lock (_lock){if (_cachedObjects==null){_cachedObjects=new Dictionary<Type, object>();}return _cachedObjects;}}}//...省略部分代碼...public object AcquireObject<TInstance>() 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];}}}

上述代碼中,我們需要定義一個(gè)全局的字典,用來存儲(chǔ)所有的單例,值得注意的是,CachedObjects 字典是一個(gè) static 類型,這表明這是一個(gè)共享的字典,不會(huì)因?yàn)椴煌腟ingletonObjectFactory對象返回不唯一的實(shí)例對象。

還有一點(diǎn),單例模式最好考慮一下多線程并發(fā)問題,雖然這是一個(gè) 『偽』 需求,畢竟Unity 3D是個(gè)單線程應(yīng)用程序,但 uMVVM 框架還是考慮了多線程并發(fā)的問題,使用 lock 關(guān)鍵字,它必須是一個(gè) static 類型,保證 lock 了同一個(gè)對象。

Transient Factory

Transient Factory 是最容易實(shí)現(xiàn)的工廠,不用考慮多線程并發(fā)問題,也不用考慮Pool,對每一次請求返回一個(gè)不同的對象:

public class TransientObjectFactory : IObjectFactory {//...省略部分代碼...public object AcquireObject<TInstance>() where TInstance : class, new(){var instance = new TInstance();return instance;}}

Pool Factory

Pool Factory 相對來說是比較復(fù)雜的工廠,它對 Transient Factory 進(jìn)行了升級(jí)——?jiǎng)?chuàng)建實(shí)例前先去Pool中看看是否有未被使用的對象,有的話,那么直接取出返回,如果沒有則向Pool中添加一個(gè)。

Pool的實(shí)現(xiàn)有兩種形式,一種是內(nèi)置了諸多對象,還有一種是初始時(shí)是一個(gè)空的池,然后再往里面添加對象。第一種效率更高,直接從池里面拿,而第二種更省內(nèi)存空間,類似于懶加載,uMVVM 的對象池技術(shù)使用第二種模式。

public class PoolObjectFactory : IObjectFactory {/// <summary>/// 封裝的PoolData/// </summary>private class PoolData{public bool InUse { get; set; }public object Obj { get; set; }}private readonly List<PoolData> _pool;private readonly int _max;/// <summary>/// 如果超過了容器大小,是否限制/// </summary>private readonly bool _limit;public PoolObjectFactory(int max, bool limit){_max = max;_limit = limit;_pool = new List<PoolData>();}private PoolData GetPoolData(object obj){lock (_pool){for (var i = 0; i < _pool.Count; i++){var p = _pool[i];if (p.Obj == obj){return p;}}}return null;}/// <summary>/// 獲取對象池中的真正對象/// </summary>/// <param name="type"></param>/// <returns></returns>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 < _pool.Count; i++){var p = _pool[i];if (!p.InUse){p.InUse = true;return p.Obj;}}if (_pool.Count >= _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);} }

上述的代碼通過構(gòu)造函數(shù)的 max 決定Pool的大小,limit 參數(shù)表示超過Pool容量時(shí),是否可以再繼續(xù)往Pool中添加數(shù)據(jù)。方法 GetObject 是最核心的方法,邏輯非常簡單,獲取對象之前先判斷Pool中是否有未被使用的對象,如果有,則返回,如果沒有,則根據(jù) limit 參數(shù)再?zèng)Q定是否可以往Pool中添加數(shù)據(jù)。

小結(jié)

工廠模式是最常見的設(shè)計(jì)模式,根據(jù)工廠的類型可以獲取不同形式的數(shù)據(jù)對象,比如單例數(shù)據(jù)、臨時(shí)數(shù)據(jù)、亦或是對象池?cái)?shù)據(jù)。這一章的工廠模式很重要,也是對下一篇對象的注入『Inject』做準(zhǔn)備,故稱之為理念先行。
源代碼托管在Github上,點(diǎn)擊此了解

轉(zhuǎn)載于:https://www.cnblogs.com/OceanEyes/p/factory_pattern.html

總結(jié)

以上是生活随笔為你收集整理的Unity应用架构设计(7)——IoC工厂理念先行的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。