1. 程式人生 > >Unity StrangeIoc框架 (二)

Unity StrangeIoc框架 (二)

MVCSContex :the big picture 

1.應用程式的入口是一個類成為ContextView,這是一個Monobehavior例項化MVCSContext

2.用MVCSContext來執行各種繫結。

3.派發器是一個通訊匯流排,允許你再程式傳送訊息,在mvcscontext中他們傳送的是TimEvents, 或者你可以按照上面的步驟重寫Context 來使用Signals

4.命令類由TimeEvents或訊號觸發,然後他會執行一些app邏輯。

5.模型儲存狀態

6.services與app意外的部分通訊(比如接入的faebook)

7.介面指令碼附加到物體上 : 玩家與遊戲的互動

8.Mediators(中介)也是monobehavior  但是他也可以將view部分和其他部分隔離開來

這張圖戰士了這些部分是如何一起工作的

大致介紹完了  下面來如何建立工程

一個ContextView開始

ContextView 是一個Monobehaviour 用來例項你的Context(上下文)  MyFirstProjectRoot 是ContextView的子類, 這裡是應用程式的開始

using System;
using UnityEngine;
using strange.extensions.context.impl;
using strange.extensions.context.api;
namespace strange.examples.myfirstproject { public class MyFirstProjectRoot : ContextView { void Awake() { //Instantiate the context, passing it this instance. context = new MyFirstContext(this,ContextStartupFlags.MANUAL_MAPPING);
       context.Start(); } } }

這裡要使用 strange.extensions.context.impl 和 using strange.extensions.context.api 名稱空間

ContextView定義了一個屬性稱為上下文當然是指我們上下文。我們只需要定義它是什麼我們寫一個叫MyFirstContext的指令碼。this 指的是MyFirstProjectRoot,他告訴Context 哪個GameObject被認為是ContextView。ContextStartupFlags.MANUAL_MAPPING表明一旦我們開始一切將會繼續。 呼叫context.Start()讓它付諸行動 。 如果不呼叫Start則不會繼續進行

  • ContextStartupFlags.AUTOMATIC  : 上下文將自動對映繫結和啟動(預設的)
  • ContextStartupFlags.MANUAL_MAPPING   : 上線文會啟動,然後在核心繫結後,在例項化或任何自定義繫結之前 將停止對映,必須呼叫Start()才可繼續進行
  • ContextStartupFlags.MANUAL_LAUNCH  :   上線文會啟動,然後在核心繫結後 , 在呼叫ContextEvent.START  或者類似的訊號前停止。必須使用Launch()繼續

The Context binds(上下文繫結)

Context(上下文)是所有繫結發生的地方,如果沒有繫結,Strange應用只是一堆斷開連線的部分。Context是為混亂帶來秩序的膠水。從我們擴充套件MVCSContext,我們得到了一大堆的核心繫結,MVCSContext是為了給我們所有我們需要乾淨的結構 一個控制反轉風格的應用:一個注射(injector)、命令匯流排、模型和服務支援,和中介介面。

using System;
using UnityEngine;
using strange.extensions.context.api;
using strange.extensions.context.impl;
using strange.extensions.dispatcher.eventdispatcher.api;
using strange.extensions.dispatcher.eventdispatcher.impl;
 
namespace strange.examples.myfirstproject
{
    public class MyFirstContext : MVCSContext
    {
 
        public MyFirstContext (MonoBehaviour view) : base(view)
        {
        }
        
        public MyFirstContext (MonoBehaviour view, ContextStartupFlags flags) : base(view, flags)
        {
        }
        
        protected override void mapBindings()
        {
            injectionBinder.Bind<IExampleModel>()
                .To<ExampleModel>()
                .ToSingleton();
            injectionBinder.Bind<IExampleService>()
                .To<ExampleService>()
                .ToSingleton();
 
            mediationBinder.Bind<ExampleView>()
                .To<ExampleMediator>();
 
            commandBinder.Bind(ExampleEvent.REQUEST_WEB_SERVICE)
                .To<CallWebServiceCommand>();
            commandBinder.Bind(ContextEvent.START)
                .To<StartCommand>().Once ();
 
        }
    }
}

像你看到的那樣,我們擴充套件了MVCSContext,這意味著我們繼承其所有對映(探索它類的深度 ,你會發現它的有趣)。我們已經有一個injectionBinder和commandBinder和dispatcher排程員。注意,排程程式可以在整個應用程式,和CommandBinder耦合,所以任何事件派遣可以觸發回撥也觸發命令commands和序列sequences。

這裡的對映是完全符合你的期待如果你讀到的各種元件注入,我們對映一個模型和一個服務都是單例。我們將只有一個檢視(ExampleView)在這個例子中,我們將它繫結到一箇中介(ExampleMediator)。最後,我們對映兩個命令。這兩個比較重要的是StartCommand繫結到一個特殊的事件:ContextEvent.START.這是事件觸發啟動你的應用。你需要繫結一些命令或者佇列到它身上想init()為進入你的應用程式。我們綁定了.Once(),一個特殊的方法,在一次結束時被解開Unbinds。

注意這裡有一個postBindings()方法。這是一個十分有用的地方放一些你需要在繫結之後執行的程式碼。但是他執行在Launch()之後,MVCSContext用這個方法去處理任何Views介面哪一個在暫存器中更早(在mapBindings之後被呼叫)。另一個明顯的和有用的情況  在postBindings()中呼叫DontDestroyOnLoad(ContextView)。在你載入一個新的場景時用來保留ContextView(and the Context)。

A Command fires(一個命令被觸發)

ContextEvent.START 被處罰,因為它被綁上了StartCommand, 一個新的StartCommand例項將被例項化出來並且執行。

using System;
using UnityEngine;
using strange.extensions.context.api;
using strange.extensions.command.impl;
using strange.extensions.dispatcher.eventdispatcher.impl;

namespace strange.examples.myfirstproject
{
    public class StartCommand : EventCommand
    {
        
        [Inject(ContextKeys.CONTEXT_VIEW)]
        public GameObject contextView{get;set;}
        
        public override void Execute()
        {
            GameObject go = new GameObject();
            go.name = "ExampleView";
            go.AddComponent<ExampleView>();
            go.transform.parent = contextView.transform;
        }
    }
}

StartCommand 擴充套件 EventCommand 意味著這是固定的命令CommandBinder可以處理, 他繼承的所有東西都來自command 和 EventCommand。特別是,繼承EventCommand意味著你得到一個IEvent注入,並且你可以訪問dispatcher。

如果你只是擴充套件命令,您不會有自動訪問這些物件,但是你依舊可以手動注入他們

[Inject(ContextKeys.CONTEXT_DISPATCHER)]
IEventDispatcher dispatcher{get;set;}

[Inject]
IEvent evt{get;set;}

注意所使用的兩種不同型別的注入。IEventDispatcher和GameObject 都是用名字建立多個例項。這是因為我們想引用這些物件的非常具體的版本。我們不希望是任意一個GameObject。我們需要一個標記像ContextView。我們也不接受任何舊IEventDispatcher。唯一一個將在上下文間通訊,他標誌為ContextKeys.CONTEXT_DISPATCHER。另一方面,Ievent是一個簡單的對映用於這個特殊的命令(技術上他對映到一個value),所以沒有必要的名字。

依賴我們將使用在當前場景是ContextView,他們新增子檢視到它。

Execute()方法通過CommandBinder自動觸發。大多數情況下 , 執行的順序是這樣的

  1. 例項化Command命令繫結到Ievent.type
  2. 注入依賴關係,包括Ievent本身
  3. 呼叫Excute()
  4. 刪除Command命令

命令不需要立即清理乾淨,但是我們將會得一點。如果你查看了Execute()裡面的程式碼,你將會發現他是純粹的Unity。建立一個GameObject,附上MonoBehaviour,然後設定它的父親為ContextView。我們使用的是具體的MonoBehaviour(程式碼),然而,恰好是一個Strange IView,自從我們在context中對映這個介面。

mediationBinder.Bind<ExampleView>().To<ExampleMediator>();

這個介面是自動排程的,這意味著一個新的ExampleMediator剛剛建立!

A View is mediated(一個介面被排程)

如果你花費了一些時間為Unity編寫程式碼,你建立一個介面,你需要呼叫Monobehavior,但是重點在於那個介面沒有在螢幕上顯示的東西。我不打算花時間執行ExampleView程式碼。你可以看下示例檔案,如果怕你已經知道C#和Unity你不需要他。我只想引起兩位的注意力。首先:

public class ExampleView : View

通過擴充套件View,你將會得到連線每個View到Context的程式碼。使用Strange 你不再需要擴充套件View或者重寫裡面的方法。但是如果你不擴充套件View,你依舊需要實現IView 介面。這需要確保你MonoBehaviour上下文可以操作。

第二項指出

[Inject]
public IEventDispatcher dispatcher{get; set;}

注意 我們注入IEventDispatcher。但是跟StartCommand不是同一個排程。仔細看看程式碼第一個寫在EventCommand(我上面顯示)是這樣的

[Inject(ContextKeys.CONTEXT_DISPATCHER)]
public IEventDispatcher dispatcher{get; set;}

通過命名注入,指定的命令使用常見的上下文排程員。這個介面不應該注入dispatcher。中介的目的是隔離應用程式的檢視 反之亦然Strange允許注入View。但這功能最好的時候嚴格限制,注入本地排程員與中介溝通很好。所以注入配置/佈局檔案(這是有用的,如果你釋出到多個平臺)。但如果你聽我的勸告,不要注入入一個模型或服務或其他池外擴充套件的檢視以及中介。

告訴你正確的方法:對於大多數開發人員來說,最難的是掌握整個框架的概念。一個檢視應該只顯示和輸入。當某些輸入發生,檢視應該通知媒體。中介Mediator(允許注入上下文排程員)抽象的觀點,關注與應用程式的其餘部分。這個保護應用程式的檢視程式碼,這通常和保護你的介面是混亂的,相反的情況是如此。

注意,基本檢視類使用標準MonoBehaviour處理程式 Awake(), Start(), and OnDestroy()。如果你重寫這些處理程式,確保你呼叫了base.Awake()等。這樣Strange才能正常執行。

觀察排程者

using System;
using UnityEngine;
using strange.extensions.dispatcher.eventdispatcher.api;
using strange.extensions.mediation.impl;

namespace strange.examples.myfirstproject
{
    public class ExampleMediator : EventMediator
    {
        [Inject]
        public ExampleView view{ get; set;}
        
        public override void OnRegister()
        {
            view.dispatcher.AddListener
                (ExampleView.CLICK_EVENT, onViewClicked);
            dispatcher.AddListener
                (ExampleEvent.SCORE_CHANGE, onScoreChange);
            view.init ();
        }
        
        public override void OnRemove()
        {
            view.dispatcher.RemoveListener
                (ExampleView.CLICK_EVENT, onViewClicked);
            dispatcher.RemoveListener
                (ExampleEvent.SCORE_CHANGE, onScoreChange);
            Debug.Log("Mediator OnRemove");
        }
        
        private void onViewClicked()
        {
            Debug.Log("View click detected");
            dispatcher.Dispatch(ExampleEvent.REQUEST_WEB_SERVICE,
                "http://www.thirdmotion.com/");
        }
        
        private void onScoreChange(IEvent evt)
        {
            string score = (string)evt.data;
            view.updateScore(score);
        }
    }
}

在最上方 我們注入了ExampleView。這是排程者Mediator如何知道排程那個介面。介質可以知道很多關於他們的介面。中介通常被認為是“廢品(信口開河的)程式碼”,因為它是非常特殊的細節檢視和應用程式。當然這個中介可以知道檢視有一個排程者和這個排程這個程式的事件成為ExampleView.CLICK_EVENT。通過監聽這個事件,中介建立了一個處理程式(onViewClicked())告訴其餘的應用這個點選意味著什麼。檢視不應該傳送REQUEST_WEB_SERVICE事件。介面只是介面。它應該像這樣派發事件HELP_BUTTON_CLICKED, COLLISION, SWIPE_RIGHT。這應該是Mediator中介者的工作,對映這些事件到應用程式的其餘有意義的部分。如REQUEST_HELP MISSILE_ENEMY_COLLISION PLAYER_RELOAD.他後面的事件對映到命令,這些命令會呼叫幫助系統,計算分數增加(增加得分模型)或確定是否允許玩家重新載入。

OnRegister()OnRemove()方法像Mediator排程者的構造與解構函式。OnRegister()在注入後發生。所以我經常用它來設定監聽和呼叫Init()方法例項介面、OnRemove()發生在Monobehavior的OnDestroy()被呼叫之後。它觸發的時候你可以用來清理監聽。確定你移除了你的監聽,否則會產生不正確的垃圾回收。

最後注意  通過擴充套件EventMediator我們有公共的dispatcher。 排程者在匯流排監聽SCORE_CHANGE事件。

Another Command fires(其他命令觸發)

讓我們看回Context  這行有我們忽略的問題:

commandBinder.Bind(ExampleEvent.REQUEST_WEB_SERVICE).To<CallWebServiceCommand>();

這裡的意思是任何時候公共的匯流排收到這個事件,它會啟動CallWebServiceCommand。但是他吸引你的注意力是因為通過不同的方法使用命令。

using System;
using System.Collections;
using UnityEngine;
using strange.extensions.context.api;
using strange.extensions.command.impl;
using strange.extensions.dispatcher.eventdispatcher.api;

namespace strange.examples.myfirstproject
{
    public class CallWebServiceCommand : EventCommand
    {
        [Inject]
        public IExampleModel model{get;set;}
        
        [Inject]
        public IExampleService service{get;set;}
 
        public override void Execute()
        {
            Retain ();
            service.dispatcher.AddListener
                (ExampleEvent.FULFILL_SERVICE_REQUEST, onComplete);
            string url = evt.data as string
            service.Request(url);
        }
        
        private void onComplete(IEvent result)
        {
            service.dispatcher.RemoveListener
                (ExampleEvent.FULFILL_SERVICE_REQUEST, onComplete);
            model.data = result.data as string;
            dispatcher.Dispatch(ExampleEvent.SCORE_CHANGE, evt.data);
            Release ();
        }
    }
}

我們監聽service,呼叫一個方法。我們使用事件中有效data資料來觸發mediator排程者service.Request(the url)。當service結束,他派發。觸發onComplate()。我們取消監聽對映,設定一個值的模型,派發SCORE_CHANGE那個哪個排程者收到就做相應的處理。

但如果你一直密切關注你會記得,我之前提到過,命令後立即清理乾淨在Execute()完成時。所以為什麼不是這個命令不會被垃圾收集。答案是最頂端呼叫Retain()方法保留。Retain()標誌著這個命令為免除清理。這將會保持知道呼叫了Release()之後。顯然,這意味著呼叫了Release()是非常重要的,否則會造成執行中的記憶體洩露風險。

不要允許模型和服務監聽事件。   利用他們的排程者來監聽事件

Mapping Across Contexts(穿過Contexts的對映)

一般來說你要遵守上下文邊界。畢竟,它的邊界是有原因的 :它允許應用程式的部分功能的隔離,使程式變得更加模組化。但有時有一些物件,也許是一個模型、一個服務、或者一個訊號需要需要跨多個上下文訪問。

injectionBinder.Bind<IStarship>().To<HeartOfGold>().ToSingleton().CrossContext();

新增CrossContext()訊號繫結需要例項化穿過context邊界。它將提供給所有孩子contexts。注意,也可以覆蓋一個CrossContext繫結。如果你隱射區域性的key,本地的繫結將會覆蓋CrossContext的那一個。

到這裡所有的文件內容已經結束了。自己著手做幾個小栗子能快速的瞭解和適應這樣的架構。架構的學習 確實可以改變人的編碼習慣 。  就這幾天對文件的閱讀,感覺收穫良多 。 希望有學習的小夥伴能夠一起交流交流。

相關推薦

Unity StrangeIoc框架

MVCSContex :the big picture  1.應用程式的入口是一個類成為ContextView,這是一個Monobehavior例項化MVCSContext 2.用MVCSContext來執行各種繫結。 3.派發器是一個通訊匯流排,允許你再程式傳送訊息,在mvcscontext中他們傳送的是T

Unity StrangeIoc框架

 最近想專案中需要使用這個架構  因此 上網看了很多資料摸索   但是對於初學者來說大多數的資料不是那麼容易理解 而且文件也是英文的閱讀起來有點吃力  所以記錄一下自己閱讀的過程  方便以後翻閱和跟我一樣的新人學習其中也借鑑了一些前輩的資料 如有反感請聯絡我   立馬進行修改  謝謝 StrangeIoc

Struts2框架 Web.xml, Struts.xml, Action.Java 基本配置

str web.xml images ava img ima blog XML ges Struts2框架(二) Web.xml, Struts.xml, Action.Java 基本配置

javascript運動框架

rip asc oat 對象 obj func 我想 lac 我們 緊接著上面寫的... 給div加一個邊框,border:1px solid black window.onload = function(){ var div = document.getEle

教你寫Http框架——三個樣例帶你深入理解AsyncTask

func implement oncreate 其它 層疊 worker dcl 例如 人員 這個標題大家不要奇怪,扯Http框架怎麽扯到AsyncTask去了,有兩個原因:首先是Http框架除了核心http理論外。其技術實現核心也是線程池 + 模板 +

Java基礎學習筆記十六 集合框架

first 哈希 cat etag 基於 col 容器 處的 新元素 List List接口的特點: 它是一個元素存取有序的集合。例如,存元素的順序是11、22、33。那麽集合中,元素的存儲就是按照11、22、33的順序完成的。 它是一個帶有索引的集合,通過索引就

很easy的js雙向綁定框架:控制器繼承

rst data 發出 sim 跟著 cti exec mar spa 初衷 上一篇已經實現了數據的雙向綁定,但model的控制範圍是整個文檔。在實際project中必需要有作用範圍,以便做ui模塊的拆分。 這一篇,我們希望實現像angularjs一

Android sensor 系統框架

port amp cap 錯誤 str 註釋 hardware war cas 連載上一篇http://www.cnblogs.com/hackfun/p/7327320.html (D) 如何加載訪問.so庫 在前一篇博客http://www.cnblogs.co

集合框架

成員 線程 aslist 建議 元素 nds 還得 編譯期 line List的子類(掌握) 1、List的子類特點 ArrayList: 底層數據結構是數組,查詢快,增刪慢 線程不安全,效率高 Vector: 底層數據結構是數組,查詢快,

spring框架

面向 int 動態代理 實現 訪問修飾符 spring pat 應用 tco Spring的bean管理(註解)   1、代碼裏面特殊標記,使用註解可以完成相應功能   2、註解寫法@註解名稱(屬性名稱=屬性值)   3、類,方法,屬性(註解使用) spring註解開

一個只有99行代碼的JS流程框架

經驗 itl 兩個 ron timeout 當前 str mmu second 歡迎大家關註騰訊雲技術社區-博客園官方主頁,我們將持續在博客園為大家推薦技術精品文章哦~ 張鎮圳,騰訊Web前端高級工程師,對內部系統前端建設有多年經驗,喜歡鉆研搗鼓各種前端組件和框架。 導

UEFI中EHCI驅動的實現框架

urb link cnblogs 異步傳輸 tro insert 傳輸 frame struct 本文從數據結構的角度看一下EHCI的初始化: 下圖是EHCI驅動中涉及的主要數據結構的關系圖: 1.Struct USB2_HC_DEV是Host controller的核心

利用 Composer 完善自己的 PHP 框架

pass 簡易 cte 郵件接收 ces api cep home ase 回顧 上一篇文章中,我們手工建造了一個簡易的視圖加載器,順便引入了錯誤處理包,讓我們的 MFFC 框架在 M、V、C 三個方面都達到了“好用”的水平。View 是一個可插拔組件,在本篇文章中我們要創

徒手擼出一個類Flask微框架路由及路由註冊的演變

pass nac 等價 themes 字典 lac found round wap 路由的基本概念:根據不同的訪問路徑調用不同的方法或者類from webob import Response,Request,dec from wsgiref.simple_server im

Java源碼解析——集合框架——ArrayBlockingQueue

not 結構 AS ray false 元素 模式 -- ins ArrayBlockingQueue源碼解析 ArrayBlockingQueue是一個阻塞式的隊列,繼承自AbstractBlockingQueue,間接的實現了Queue接口和Collection接口

Windows環境下,從零開始搭建Nodejs+Express+Ejs框架---安裝Express,ejs

所有 nod 環境 安裝目錄 關於 str 列表 ima 執行 安裝Express,ejs的前提是一定要先安裝nodejs,具體安裝方法請查看 http://www.cnblogs.com/tfiremeteor/p/8973105.html 安裝Express和ejs的前

JavaWeb學習之Hibernate框架

utils xtend auto etl SQ dial begin 可選 oct hibernateAPI詳解 Configuration 創建 加載主配置 創建sessionFactory

分布式服務框架

無限 快速 異常 net iyu 成熟 基礎上 管理平臺 感知 一、分布式服務框架其他組成   上一節《分布式服務框架(一)》講述了RPC發展到SOA的過程,常見的SOA服務治理方案,以及分布式系統中常見的專業名詞,這部分其實只是涉及到了一個分布式系統架構的輪廓,真正一個系

ATK-DataPortal 設計框架

開源中國 mes -- 上下 urn 通用 mar ESS rate 在信息的交換過程中,總是有此相同相似的功能,由於業務的各自不同,由同一類型來處理諸如增刪改查等常見的信息處理方式。從日常的對些類行為操作為生成的類分析,大量雷同的代碼遍布整個項目。框架中xxxHandel

初識gauge自動化測試框架

numbers 引用 文件中 自動化測試 文件描述 tor 興趣 測試 你是 看到一些同學對該工具有點一興趣,那麽我將繼續介紹Gauge自動化測試工具。 Gauge本質上一個BDD(Behavior Driven Development)測試框架。所以,首先你要了解BDD的