Unity StrangeIoc框架 (一)
最近想專案中需要使用這個架構 因此 上網看了很多資料摸索 但是對於初學者來說大多數的資料不是那麼容易理解 而且文件也是英文的閱讀起來有點吃力 所以記錄一下自己閱讀的過程 方便以後翻閱和跟我一樣的新人學習其中也借鑑了一些前輩的資料 如有反感請聯絡我 立馬進行修改 謝謝
StrangeIoc 是依據控制反轉和解耦原理設計的,支援依賴注入。
控制反轉即Ioc(Inversion of Control) 它把傳統上由程式程式碼直接操控的物件的呼叫權交給容器,通過容器來實現物件元件的裝配和管理。所為的“控制反轉”概念就是對元件物件控制權的轉移,從程式程式碼本身轉移到了內部的容器。
依賴注入(Dependency Injection) 依賴注入的基本原則是:應用元件不應該負責查詢資源或者其他依賴的寫作物件。配置物件的工作應該由Ioc容器負責,
在使用時
Bingding(繫結)
strange的核心是繫結,我們可以將一個或多個物件與另外一個或多個物件繫結(連線)在一起,將介面與類繫結來實現介面,將事件與事件接收繫結在一起。或者繫結兩個類,一個類被建立時另一個類自動建立。
strange的binding由兩個必要部分和一個可選部分組成,必要部分是a key and a value key觸發value,因此一個事件可以觸發回撥,一個類的例項化可以觸發另一個類的例項化。可選部分是name,他可以區分使用相同key的兩個binding 下面三種繫結方法其實都是一樣的,語法不同而已
1. Bind<IRoundLogic>().To<RoundLogic>(); 2. Bind(typeof(IRoundLogic)).To(typeof(RoundLogic)); 3. IBinding binding = Bind<IRoundLogic>(); //使用IBinding 的時候需要引用strange.framework.api; 名稱空間 binding.To<RoundLogic>();
Bind<IRoundLogic>().To<RoundLogic>().ToName(“Logic”); //使用非必要部分name
繫結從層次上分為3種: injectionbinding ,commandbinding, mediationbing
注入繫結injectionbinding主要是用來繫結該型別物件到上下文,這樣使得程式中各個地方可以通過contextview訪問得到該物件。這種繫結會生成物件。這種繫結是為了生成物件並且注入到指定物件中用的
commandbinding是為了將命令繫結到方法中用的
mediationbing則是為了攔截view訊息,而將view注入中介mediator中,然後在view的awake方法裡面生成meidtaor物件
The injection extension(注入擴充套件)
在繫結擴充套件中最接近控制反轉的思想是注入
介面本身沒有實現方法,只定義類中的規則
interface ISpaceship { void input(float angle, float velocity); IWeapon weapon{get;set;} } //使用另一個類實現這個介面,寫法如下 Class Spaceship : ISpaceship { public void input(float angle, float velocity) { //do } public IWeapon weapon{get;set;} }
如果採用上面的寫法,Spaceship類裡面不用再寫檢測輸入的功能了,只需要處理輸入就可以了input只需要控制移動,不需要管是何種輸入方式 是手柄鍵盤或是其他 只需要進行處理
也不需要武器的邏輯,僅僅是注入武器例項就可以了。但是我們需要知道武器是什麼樣的武器 不同的武器造成不同的掉血 所以這塊的邏輯是需要處理的
public interface IWeapon
{
void Attack();
}
public class PhaserGun : IWeapon
{
public void Attack(){//掉血邏輯
}
}
public class SquirtCannon : IWeapon
{
public void Attack(){//掉血邏輯
}
}
在ISpaceship中的程式碼進行一點修改
interface ISpaceship { void input(float angle, float velocity); [Inject] IWeapon weapon{get;set;} }
加上Inject標籤 這樣就可以進行綁定了 將介面與類繫結來實現介面
[Inject]標籤實現介面,而不是例項化類
injectionBinder.Bind<IWeapon>().To<PhaserGun >();
單例對映
injectionBinder.Bind<IWeapon>().To<PhaserGun >().ToStringleton();
IWeapon weapon = PhaserGun.Get();
在繫結多個的時候就需要利用 名稱對映來進行區分
injectionBinder.Bind<ISocialService>() .To<TwitterService>().ToSingleton() .ToName(ServiceTypes.PRIMARY); injectionBinder.Bind<ISocialService>() .To<TwitterService>().ToSingleton() .ToName(ServiceTypes.SECONDARY); injectionBinder.Bind<ISocialService>() .To<TwitterService>().ToSingleton() .ToName(ServiceTypes.TERTIARY);
在[Inject]標籤處 也需要進行新增名稱
[Inject (ServiceTypes.TERTIARY)] //We mapped TwitterService to TERTIARY public ISocialService socialService{get;set;}
值的對映
Configuration myConfig = loadConfiguration(); injectionBinder.Bind<IConfig>().ToValue(myConfig);
具體還有幾種對映就不說了 需要的可以去看看文件
The reflector extension(反射擴充套件)
反射列表
List<Type> list = new List<Type> (); list.Add (typeof(Borg)); list.Add (typeof(DeathStar)); list.Add (typeof(Galactus)); list.Add (typeof(Berserker)); //count should equal 4, verifying that all four classes were reflected. int count = injectionBinder.Reflect (list);
反射所有已經通過injectionBinder對映的所有
injectionBinder.ReflectAll();
The dispatcher extension(排程程式擴充套件)
dispatcher相當於觀察者模式中的公告板,允許客戶監聽他,並且告知當前發生的事件。在strangeioc中,通過EventDispatcher方式實現,EventDispatcher繫結觸發器來觸發帶引數/不帶引數的方法 觸發器通常是String或列舉型別(觸發器可以理解為key,或者事件的名稱,名稱對應著觸發的方法)
如果有返回值,他將存在IEvent,一個簡單的值物件包含與該事件相關的任何資料,你可以寫你自己的事件滿足IEvent介面,strangeioc事件叫TmEvent
如果你再使用MVCSContext 有一個全域性的EventDispatcher 叫contextDispatcher 會自動注入,你可以用來傳遞事件
有兩種基本的事你可以去做EventDipatcher排程事件和監聽他們
dispatcher.AddListener("FIRE_MISSILE", onMissileFire);
事件會處於監聽狀態,知道FIRE_MISSILE事件被處罰,然後執行對應的onMissileFire方法
也可以通過列舉實現
dispatcher.AddListener(AttackEvent.FIRE_MISSILE, onMissileFire);
移除監聽
dispatcher.RemoveListener(AttackEvent.FIRE_MISSILE, onMissileFire);
更新監聽
dispatcher.UpdateListener(true, AttackEvent.FIRE_MISSILE, onMissileFire);
呼叫的方法可以有一個引數或者沒有,這取決於你關心的事件效率
private void onMissileFire() { //this works... } private void onMissileFire(IEvent evt) { //...and so does this. Vector3 direction = evt.data as Vector3; }
排程事件
dispatcher.Dispatch(AttackEvent.FIRE_MISSILE);
這種形式的排程將生成一個新的TmEvent 呼叫任何監聽物件,但是因為你沒有提供資料,資料欄位的TmEvent當然會是零。 你也可以排程和提供資料:
Vector3 orientation = gameObject.transform.localRotation.eulerAngles; dispatcher.Dispatch(AttackEvent.FIRE_MISSILE, orientation);
可以自己建立TmEvent排程
Vector3 orientation = gameObject.transform.localRotation.eulerAngles;
TmEvent evt = new TmEvent(AttackEvent.FIRE_MISSILE, dispatcher, this.orientation); dispatcher.Dispatch(evt);
The command extension(命令擴充套件)
除了繫結事件的方法,可以將其繫結到Commands。命令是控制器結構MVC的指揮者在strangeioc的MVCSContext中CommandBinder監聽每一個dispatcher的排程(當然你可以改變這個如果你想在自己的上下文)。訊號,下面描述,也可以繫結到命令。當一個事件或訊號被排程,
using strange.extensions.command.impl; using com.example.spacebattle.utils; namespace com.example.spacebattle.controller { class StartGameCommand : EventCommand { [Inject] public ITimer gameTimer{get;set;} override public void Execute() { gameTimer.start(); dispatcher.dispatch(GameEvent.STARTED); } } }
但非同步命令, 像網路請求 可以這樣做 Retain()
and Release()
using strange.extensions.command.impl; using com.example.spacebattle.service; namespace com.example.spacebattle.controller { class PostScoreCommand : EventCommand { [Inject] IServer gameServer{get;set;} override public void Execute() { Retain(); int score = (int)evt.data; gameServer.dispatcher.AddListener(ServerEvent.SUCCESS, onSuccess); gameServer.dispatcher.AddListener(ServerEvent.FAILURE, onFailure); gameServer.send(score); } private void onSuccess() { gameServer.dispatcher.RemoveListener(ServerEvent.SUCCESS, onSuccess); gameServer.dispatcher.RemoveListener(ServerEvent.FAILURE, onFailure); //...do something to report success... Release(); } private void onFailure(object payload) { gameServer.dispatcher.RemoveListener(ServerEvent.SUCCESS, onSuccess); gameServer.dispatcher.RemoveListener( ServerEvent.FAILURE, onFailure); //...do something to report failure... Release(); } } }
如果使用完不進行Release()可能會導致記憶體洩露
對映命令
commandBinder.Bind(ServerEvent.POST_SCORE).To<PostScoreCommand>();
您可以將多個命令繫結到單個事件如果你喜歡
commandBinder.Bind(GameEvent.HIT).To<DestroyEnemyCommand>().To<UpdateScoreCommand>();
解除命令繫結Unbind
commandBinder.Unbind(ServerEvent.POST_SCORE);
一次性的指令
commandBinder.Bind(GameEvent.HIT).To<DestroyEnemyCommand>().Once();
按順序執行繫結 InSequence 會一直執行到最後的命令 或者其中一個命令失敗。 命令可以在任何時候呼叫Fail() 這會打破這個序列 這可以用於建立一個鏈相關的事件 為構建有序的動畫,或制定一個守衛,以確定是否應該執行一個命令。
commandBinder.Bind(GameEvent.HIT).InSequence() .To<CheckLevelClearedCommand>() .To<EndLevelCommand>() .To<GameOverCommand>();
The signal extension(訊息擴充套件)
訊號是一個排程機制,另一種選擇EventDispatcher 相比於EventDispatcher 訊號有兩個優點 1. 分發結果不再建立例項,因此也不需要GC回收更多的辣雞 2. 更安全 當訊息與回撥不匹配時會斷開執行,官網也推薦使用Singal來相容後續版本
建立兩個訊號,每一個都有一個引數
Signal<int> signalDispatchesInt = new Signal<int>(); Signal<string> signalDispatchesString = new Signal<string>();
signalDispatchesInt.AddListener(callbackInt); //Add a callback with an int parameter
signalDispatchesString.AddListener(callbackString); //Add a callback with a string parameter
signalDispatchesInt.Dispatch(42); //dispatch an int
signalDispathcesString.Dispatch("Ender wiggin"); //dispatch a string
void callbackInt(int value){
//Do something with this int
}
void callbackString(string value){
//Do something with this string
}
訊息最多可以使用四個引數
Signal<T, U, V, W> signal = new Signal<T, U, V, W>();
子類可以編寫自己的訊號
using System; using UnityEngine; using strange.extensions.signal.impl; namespace mynamespace { //We're typing this Signal's payloads to MonoBehaviour and int public class ShipDestroyedSignal : Signal<MonoBehaviour, int> { } }
訊號對映到命令
protected override void addCoreComponents() { base.addCoreComponents(); injectionBinder.Unbind<ICommandBinder>(); injectionBinder.Bind<ICommandBinder>().To<SignalCommandBinder>().ToSingleton(); }
這告訴strangeioc 我們做了預設CommandBinder SignalCommandBinder取而代之。 所以是訊號觸發命令 而不是事件 。 strangeioc 只支援 事件或者訊號中的一個對映命令,而不是兩個都是。
訊號繫結 依舊使用commandBinder
commandBinder.Bind<SomeSignal>().To<SomeCommand>();
對映一個訊號到命令 會自動建立一個injection對映 你可以通過[Inject]標籤 檢索
[Inject] public ShipDestroyedSignal shipDestroyedSignal{get; set;}
commandBinder.Bind<ShipDestroyedSignal>().To<ShipDestroyedCommand>();
在ShipMediator,我們注入訊號,然後排程
[Inject] public ShipDestroyedSignal shipDestroyedSignal{get; set;} private int basePointValue; //imagining that the Mediator holds a value for this ship //Something happened that resulted in destruction private void OnShipDestroyed() { shipDestroyedSignal.Dispatch(view, basePointValue); }
派遣一個訊號通過SignalCommandBinder對映結果的例項化ShipDestroyedCommand:
using System; using strange.extensions.command.impl; using UnityEngine; namespace mynamespace { //Note how we extend Command, not EventCommand public class ShipDestroyedCommand : Command { [Inject] public MonoBehaviour view{ get; set;} [Inject] public int basePointValue{ get; set;} public override void Execute () { //Do unspeakable things to the destroyed ship } } }
如您所見,對映的方法非常類似於訊號命令的方法使用事件
兩個重要問題:第一,而訊號支援多個相同型別的引數,注射。 因此不可能對一個訊號與相同型別的兩個引數對映到一個命令
//This works Signal<int, int> twoIntSignal = new Signal<int, int>(); twoIntSignal.AddListener(twoIntCallback); //This fails Signal<int, int> twoIntSignal = new Signal<int, int>(); commandBinder.Bind(twoIntSignal).To<SomeCommand>();
override public void Launch() { base.Launch(); //Make sure you've mapped this to a StartCommand! StartSignal startSignal= (StartSignal)injectionBinder.GetInstance<StartSignal>(); startSignal.Dispatch(); }
對映沒有命令的訊號
一個訊號對映到一個命令會自動建立一個對映,您可以檢索通過注入到其他地方 但是如果你想注入訊號沒有繫結到一個命令 使用injectionBinder只需將它對映
injectionBinder.Bind<ShipDestroyedSignal>().ToSingleton();
The mediation extension(調解器(中介模式))
MediationContext是唯一一個專為unity設計的部分,因為mediation關心的是對view(GameObject)的操作。由於view部分天生的不確定性,我們推薦view由兩種不同的monobehavior組成:View and Mediator
view就是mvc中的v,一個view就是一個你可以編寫的邏輯,控制可見部分的monobehavior 這個類可以附加(拖拽)到unity編輯器來管理GameObject 但是不建議將mvc中的models和controller邏輯解除安裝view中
Mediator類的職責是執行view和整個應用的執行。他會獲取整個app中分發和接收時間和訊息。但是因為mediator的設計,建議使用命令模式(command)來做這部分功能
using Strange.extensions.mediation.impl; using com.example.spacebattle.events; using com.example.spacebattle.model; namespace com.example.spacebattle.view { class DashboardMediator : EventMediator { [Inject] public DashboardView view{get;set;} override public void OnRegister() { view.init(); dispatcher.AddListener (ServiceEvent.FULFILL_ONLINE_PLAYERS, onPlayers); dispatcher.Dispatch (ServiceEvent.REQUEST_ONLINE_PLAYERS); } override public void OnRemove() { dispatcher.RemoveListener (ServiceEvent.FULFILL_ONLINE_PLAYERS, onPlayers); } private void onPlayers(IEvent evt) { IPlayers[] playerList = evt.data as IPlayers[]; view.updatePlayerCount(playerList.Length); } } }
1.DashboardView注入可以使 Mediator 知道具體的view
2.注入完成後OnRegister()方法會立即執行,可以用這個方法來做初始化 像上面做的那樣 初始化 然後做重要的資料請求
3.contextDispatcher可以擴充套件任何的EventMediator
4.OnRemove()清理時使用,當一個view銷燬前被呼叫,移除時記得刪除你的監聽
5.例子中的view暴露兩個介面init()和updatePlayerCount(float value),但是程式在設計時 你需要更多,但是原則是相同的 限制中介除了薄任務之間的傳遞資訊的檢視和其他應用程式
繫結一個介面到Mediator
mediationBinder.Bind<DashboardView>().To<DashboardMediator>();
值得注意的幾點
1.不是所有的MonoBehaviour被限制為一個View
2.中介者繫結是例項對例項的,也就是說一個view對應一個mediator,如果有很多view,也就會有很多的mediator
The context extension(上下文擴充套件)
MVCSContext包含EventDispatcher(事件分發),injectionBinder(注入繫結),MediationBinder(中介繫結),CommandBinder(命令繫結)
可以重新將CommandBinder繫結到SignalCommandBinder 命令和中介依託注入,context可以為命令和中介的繫結提供關聯
建立一個專案,需要重新MVCSContext或者Context,一個app也可以包換多個Contexts 這樣可以使你的app更高的模組化,因此,一個app可以獨立的設計為聊天模組,社交模組 最終他們會整合到一起成為一個完整的app
相關推薦
Unity StrangeIoc框架 (一)
最近想專案中需要使用這個架構 因此 上網看了很多資料摸索 但是對於初學者來說大多數的資料不是那麼容易理解 而且文件也是英文的閱讀起來有點吃力 所以記錄一下自己閱讀的過程 方便以後翻閱和跟我一樣的新人學習其中也借鑑了一些前輩的資料 如有反感請聯絡我 立馬進行修改 謝謝 StrangeIoc
Unity StrangeIoc框架 (二)
MVCSContex :the big picture 1.應用程式的入口是一個類成為ContextView,這是一個Monobehavior例項化MVCSContext 2.用MVCSContext來執行各種繫結。 3.派發器是一個通訊匯流排,允許你再程式傳送訊息,在mvcscontext中他們傳送的是T
Unity3D的MVC框架(一)——StrangeIOC與Extension的擴充套件介紹
Unity3D的MVC框架(一)——Strange IOC與Extension的擴充套件介紹 StrangeIoC框架是一個超輕量級和高度可擴充套件反轉(IOC)框架,專門為c#和Unity編寫,它是基於MVC框架擴充套件的。即MVCS框架。M(models),
用Unity實現AR類爐石傳說遊戲——開發框架(一)
遊戲流程圖 玩家類 每場對戰中有兩個玩家例項 每個玩家擁有: 卡組 牌庫 手牌 場上的英雄 生命值,能量值等屬性 卡組 vector作為容器儲存 vector<Card> CardsCombination; 由
【SSH之旅】一步步學習Hibernate框架(一):關於持久化
stc localhost 對象 schema hbm.xml java let pass [] 在不引用不論什麽框架下,我們會通過平庸的代碼不停的對數據庫進行操作,產生了非常多冗余的可是又有規律的底層代碼,這樣頻繁的操作數據庫和大量的底層代碼的反復
基於 EntityFramework、Autofac 的 UnitOfWork 框架(一)
map 包括 應用 問題 pos web 新的 ges 解釋 之前公司項目參考 NopCommerce 開發了一套系統,但是不支持 UnitOfWork,最近想開發新的項目,所以就基於原有的基礎上又添加 UnitOfWork 支持,由於目前正在逐步完善中,所以可能存在各種問
web框架(一)之基礎簡介
-a 程序 我想 pos 客戶 創建 當前 自動 art http的請求聲明周期:域名----DNS服務器---IP地址---基於tcp協議的http協議發送請求協議,服務端返回響應頭+響應體(我們所看到的頁面(是經過js渲染的,接收的是字符串))服務端(web服務)根據我
自制權限框架(一)jsp標簽
目錄 用戶 request ref 基於 -i rar 發現 tro 一、概述 在我們的系統中,很多時候都用到了權限。最簡單的權限就是登錄。登錄了,我就可以自己的相關信息;沒有登錄,就不能看到。 目前比較流行的權限框架就是apache shiro和spring se
MyBatis框架(一)
通過 ons sql dstat ride 開源 alt div feed MyBatis介紹: MyBatis 本是apache的一個開源項目iBatis, 2010年這個項目由apache software foundation 遷移到了google code,並且
Spring框架(一)
原因 getmethod 意思 myba model 找我 except 類型 程序代碼 Spring: Spring是一個開源框架,Spring是於2003 年興起的一個輕量級的Java 開發框架,由 Rod Johnson在其著作 Expert One-On-On
編寫python web框架(一):簡介
== web 方法 nvi ever pytho 必須 ext sim 編寫一個最簡單的應用: def app(environ, start_response): start_response(‘200 OK‘, [(‘Content-Type‘, ‘tex
我為什麽支持高校的業務系統放棄Apache Struts2框架(一)
文章 廣東 我們 然而 所有 以及 erl 業務 spring 月初聽聞廣東某高校(中山大學)發布通知:關於停止使用Apache Struts2開發框架的通知 鑒於S2漏洞較多、維護難度較大,為防範控制網絡安全風險,經研究決定,新建信息化項目不得使用S2; 在用S2的信息
Skynet服務器框架(一) Linux下的安裝和啟動
進行 harbor 的人 新源 中心 -a 編譯 加載模塊 問題 根據雲風博客的描述,Skynet 的核心功能就是解決一個問題: 把一個符合規範的 C 模塊,從 動態庫(so文件)中啟動起來,綁定一個永不重復(即使模塊退出)的數字id做為其 handle。模塊 被稱為
利用 Composer 一步一步構建自己的 PHP 框架(一)
highlight odi yii 2 org lar getc group bsp 空間 “一個時代結束了,另一個時代開始了。” Framework Interoperability Group(框架可互用性小組),簡稱 FIG,成立於 2009 年。FIG 最初由幾位知
Java源碼解析——集合框架(一)——ArrayList
cloneabl trac RR ... 需要 pub 復雜 每次 靈活 ArrayList源碼分析 ArrayList就是動態數組,是Array的復雜版本,它提供了動態的增加和減少元素、靈活的設置數組的大小。 一、類聲明 public class ArrayLi
Windows環境下,從零開始搭建Nodejs+Express+Ejs框架(一)---安裝nodejs
直接 分享圖片 完成 info pre download png 安裝包 get 第一步,安裝nodejs https://nodejs.org/en/download/ 這個是nodejs的官網,由於操作系統是win7 64位的,所以,我下載的是node-v8.11.1-
TensorFlow框架(一) 張量、計算圖、會話
type ont 權重 src target col flow imp mooc 參考:中國大學MOOC 北京大學 曹健《TensorFlow筆記》 基於TensorFlow的NN:用張量表示數據,用計算圖搭建神經網絡,用會話執行計算圖,優化線上的權重(參數),得
Asp.net MVC 搭建屬於自己的框架(一)
C4D pagedlist del tran 6.0 ext 才有 應該 frame 網址:https://www.cnblogs.com/sggx/p/4555255.html 為什麽要自己搭框架? 大家夥別急,讓我慢慢地告訴你!大家有沒有這種感覺,從一家跳槽到另一家
分布式服務框架(一)
不能 企業應用 service ide 宕機 因此 style 質量 作用 一、RPC RPC(Remote Process Call),即遠程服務調用,被廣泛地應用在很多企業應用中,是早期主要的服務治理方案,其流程較為簡單,客戶端consumer攜帶參數發送RPC請求
初探AngularJs框架(一)
{} ack -o fff ati gist htm bootstra 如果 一、需要準備的環境 Nodejs:https://nodejs.org/en/download/ Python:https://www.python.org/downloads/