對於開發者來說,一個好的依賴注入框架會大幅提高代碼的可讀性、可測試性和靈活性。很多框架都只是提供了一個基礎的依賴注入功能,但 StrangeIoC 這個框架的特點就是強大到可以為你的整個應用程序管理依賴和組件。
一、StrangeIoC 框架的概述
StrangeIoC 是用於 Unity3D 遊戲引擎的依賴注入框架,可以幫助 Unity 開發者更好的構建應用程序。這個框架以依賴注入和解耦為目標來設計,主要由三個部分組成:Bind、Injection、CrossContext。
1. Bind
Bind 是這個框架的核心部分,它是為了構建綁定關係的。當你需要將某些類型綁定到另外一些類型時,Bind 就是你需要使用的工具。Bind 是由一個 Binder 類型來掌控的。而 Binder 又用一個 Binding 類來表達綁定信息,它們之間的關係如下圖所示:

在圖中,你可以看到 Binder 中包含了一個 Binding 的字典,Binding 表示了一個綁定關係。對於一個類型來說,它可以綁定到多個 Binding 上,但每個 Binding 只能被一個類型綁定。在使用 Bind 進行綁定時,通常需要指定一個綁定的鍵值,這個鍵值可以是一個類型、字元串或對象等,但必須保證唯一。
2. Injection
Injection 即插入,是這個框架的第二個部分。它主要是通過依賴注入的方式向對象中注入所需的依賴。你可以通過兩種方式來進行注入:屬性注入和構造函數注入。
屬性注入:在類中定義屬性,並用 [Inject] 標記標記需要注入的屬性,StrangeIoC 將會在對象被注入時將綁定的類型實例自動注入到它們的對象中。
“`csharp
public class SomeComponent : MonoBehaviour {
[Inject]
public SomeService SomeService { get; set; }
// …
}
“`
構造函數注入:在類的構造函數中加入依賴參數,並用 [Inject] 標記標記需要注入的參數類型,StrangeIoC 將會在對象被注入時將綁定的類型實例自動注入到它們的對象中。
“`csharp
public class SomeComponent : MonoBehaviour {
private readonly SomeService _someService;
[Inject]
public SomeComponent(SomeService someService) {
_someService = someService;
}
// …
}
“`
3. CrossContext
CrossContext 處理的是跨上下文的依賴關係,在應用程序中設計良好的上下文管理可以大幅度提高應用程序的性能。StrangeIoC 框架為上下文管理提供了很好的支持,當需要處理不同上下文之間的依賴關係時,只需要導入 CrossContext,即可實現上下文間的交互。
二、StrangeIoC 的使用方法
下面我們來看一下 StrangeIoC 的實際使用方法。
1. 安裝
在 Unity 的 Package Manager 中選擇 Add package from git URL 並輸入 git@github.com:strangeioc/strangeioc.git 即可安裝。
2. 綁定類型
在使用 StrangeIoC 進行綁定之前,需要確認以下幾點:
1. 被綁定的類型必須是已經在場景中或預製體中存在的。
2. 綁定是全局的,不同的上下文之間共享綁定關係。
3. 使用構造函數注入時,你需要確保類型的所有依賴都也進行了綁定。
“`csharp
using strange.extensions.context.impl;
using strange.extensions.injector.api;
using UnityEngine;
public class BindToInstanceSample : ContextView
{
private void Awake()
{
var context = new Context(this);
context.injectionBinder.Bind().To();
context.injectionBinder.Bind().To()
.ToSingleton() // ToSingleton 表示單例綁定
.ToName(“Soldier”); // 給綁定關係起個名字
}
}
public class Soldier : ISoldier
{
[Inject] public IWeapon Weapon { get; set; }
public void Attack()
{
Debug.Log($”Using {Weapon.Name} to attack!”);
}
}
public class Knife : IWeapon
{
public string Name => “Knife”;
}
“`
在上面的代碼中,我們將 IWeapon 介面綁定到 Knife 類型上,將 ISoldier 介面綁定到 Soldier 上,並設置了 Soldier 為 Singleton 單例,同時給它起了個名字 Soldier。
3. 注入依賴
在上面的綁定代碼中,使用了屬性注入和構造函數注入兩種方式來注入依賴。
在 PropsInjectionSample 中,我們使用屬性注入方式向 Soldier 對象中注入 IWeapon 對象:
“`csharp
using strange.extensions.context.impl;
using UnityEngine;
public class PropsInjectionSample : ContextView
{
[SerializeField] private Knife knife;
private void Awake()
{
var context = new Context(this);
context.injectionBinder.Bind().To(() => knife).ToSingleton();
context.injectionBinder.Bind().To().ToSingleton();
}
}
“`
在上面的代碼中,將 IWeapon 綁定到 Knife 類型上,並使用 To 方法,將注入對象作為一個函數傳遞,這樣,每次調用 Inject 方法時,將會調用該函數來獲得注入對象。
在 ConstructInjectionSample 類中,我們使用構造函數注入方式向 Soldier 對象中注入 IWeapon 對象:
“`csharp
using strange.extensions.context.impl;
using UnityEngine;
public class ConstructInjectionSample : ContextView
{
[SerializeField] private Knife knife;
private void Awake()
{
var context = new Context(this);
context.injectionBinder.Bind().To(() => knife).ToSingleton();
context.injectionBinder.Bind().To().ToSingleton();
}
private class SoldierWithConstruct : ISoldier
{
private readonly IWeapon _weapon;
public SoldierWithConstruct(IWeapon weapon)
{
_weapon = weapon;
}
public void Attack()
{
Debug.Log($”Using {_weapon.Name} to attack!”);
}
}
}
“`
在上面的代碼中,我們創建了一個新的 SoldierWithConstruct 類,由於 SoldierWithConstruct 存在一個 IWeapon 類型的參數,StrangeIoC 將會使用構造函數注入方式來創建這個對象,並將 IWeapon 對象自動注入進去。
三、StrangeIoC 的高級應用
在正式的應用程序中,你需要更加靈活的控制組件和依賴。下面簡單介紹一下 StrangeIoC 的高級應用。
1. 模塊化開發
由於綁定關係都是全局的,不同模塊之間可能會有命名上的衝突。因此,我們可以使用子綁定器來實現模塊化開發。
“`csharp
using strange.extensions.command.api;
using strange.extensions.command.impl;
using strange.extensions.context.api;
using strange.extensions.context.impl;
using strange.extensions.dispatcher.eventdispatcher.api;
using strange.extensions.dispatcher.eventdispatcher.impl;
using strange.extensions.injector.api;
using strange.extensions.injector.impl;
using UnityEngine;
public class ModuleSample : ContextView
{
public static IInjectionBinder MainBinder;
private void Awake()
{
var context = new Context(this, ContextStartupFlags.MANUAL_LAUNCH);
context.injectionBinder.BinderName = “MainBinder”;
MainBinder = context.injectionBinder;
context.Start();
var subContext = new ModuleContext(this);
subContext.Start();
}
public class CommonBundleInstaller : IInstaller
{
public void Install(IInjectionBinder binder)
{
binder.Bind().To().ToSingleton();
}
}
public class ModuleContext : MVCSContext
{
public ModuleContext(MonoBehaviour view) : base(view, ContextStartupFlags.MANUAL_LAUNCH)
{
}
protected override void mapBindings()
{
injectionBinder.BinderName = “SubBinder”;
injectionBinder.Install(new CommonBundleInstaller());
commandBinder.Bind().To();
}
}
public interface IFoo
{
}
public class Foo : IFoo
{
}
public class SomeEventCommand : EventCommand
{
[Inject] public IFoo Foo { get; set; }
public override void Execute()
{
Debug.Log(“Do something with Foo instance.”);
}
}
}
public class SomeEvent : IEvent
{
}
“`
在上面的例子中,我們定義了一個 CommonBundleInstaller 類,用於安裝一些共享模塊的綁定關係;然後我們定義了一個名為 SubBinder 的 subContext,它是 MVCSContext 的一個派生類,它也有一個自己的綁定器。
2. 自定義命令綁定
在 StrangeIoC 中,命令綁定是用來處理用戶事件的,它們綁定到事件上,並且當事件被觸發時,命令將會被執行。你可以通過自定義命令來擴展 StrangeIoC 的功能。
“`csharp
using strange.extensions.command.impl;
using strange.extensions.context.api;
using strange.extensions.context.impl;
using strange.extensions.dispatcher.eventdispatcher.api;
using strange.extensions.dispatcher.eventdispatcher.impl;
using strange.extensions.injector.api;
using strange.extensions.injector.impl;
using UnityEngine;
public class CustomCommandBindingSample : ContextView
{
private void Awake()
{
var context = new Context(this);
context.commandBinder.Bind().To();
context.dispatcher.Dispatch(new SomeEvent { IntValue = 10 });
}
public class SomeEvent : IEvent
{
public int IntValue { get; set; }
}
public class MultiplyCommand : Command
{
[Inject] public int Multiplier { get; set; } = 3;
public override void Execute()
{
var e = evt.data as SomeEvent;
Debug.Log(e.IntValue * Multiplier);
}
}
}
“`
在上面的例子中,我們定義了一個自定義命令 MultiplyCommand,將 SomeEvent 和 MultiplyCommand 進行綁定綁定。在命令類中,我們可以通過 [Inject] 標記來注入依賴項。由於依賴注入是自動完成的,我們可以在命令類中直接使用注入的對象來進行計算。
3. 自定義綁定提供者
StrangeIoC 默認支持的綁定關係是有限的,例如綁定一個類型到另一個類型需要指定 .To 方法,但是如果你想通過其他的方式來定義綁定關係呢?在 StrangeIoC 中,你可以通過實現 IBindingProvider 介面來自定義綁定關係。
“`csharp
using System;
using strange.extensions.context.impl;
using UnityEngine;
public class CustomBindingProviderSample : ContextView
{
private void Awake()
{
var context = new Context(this);
context.injectionBinder.Unbind();
context.injectionBinder.Bind().ToProvider(new RandomNumberProvider());
var entity = new Entity(context.injectionBinder.GetInstance());
Debug.Log($”Entity instance ID={entity.InstanceId}, value={entity.Value}”);
}
private class Entity
{
public int InstanceId { get; private set; }
public int Value { get; private set; }
public Entity(int value)
{
InstanceId = GetHashCode();
Value = value;
}
}
private class RandomNumberProvider : IBindingProvider
{
public Type GetBindingType()
{
return typeof(int);
}
public object GetBinding(IInjectionBinder binder)
{
return new System.Random().Next(100);
}
}
}
“`
在上面的例子中,我們實現了 IBindingProvider 介面,用於生成隨機數綁定關係。在 Entity 類的構造函數中通過 StrangeIoC 注入的方式注入一個隨機數。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/246903.html