强大的依赖注入框架 StrangeIoC

对于开发者来说,一个好的依赖注入框架会大幅提高代码的可读性、可测试性和灵活性。很多框架都只是提供了一个基础的依赖注入功能,但 StrangeIoC 这个框架的特点就是强大到可以为你的整个应用程序管理依赖和组件。

一、StrangeIoC 框架的概述

StrangeIoC 是用于 Unity3D 游戏引擎的依赖注入框架,可以帮助 Unity 开发者更好的构建应用程序。这个框架以依赖注入和解耦为目标来设计,主要由三个部分组成:Bind、Injection、CrossContext。

1. Bind

Bind 是这个框架的核心部分,它是为了构建绑定关系的。当你需要将某些类型绑定到另外一些类型时,Bind 就是你需要使用的工具。Bind 是由一个 Binder 类型来掌控的。而 Binder 又用一个 Binding 类来表达绑定信息,它们之间的关系如下图所示:

![Binder和Binding的关系](pic/binder_binding.png)

在图中,你可以看到 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/n/246903.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-12 13:18
下一篇 2024-12-12 13:18

相关推荐

  • Ojlat:一款快速开发Web应用程序的框架

    Ojlat是一款用于快速开发Web应用程序的框架。它的主要特点是高效、易用、可扩展且功能齐全。通过Ojlat,开发人员可以轻松地构建出高质量的Web应用程序。本文将从多个方面对Oj…

    编程 2025-04-29
  • Zlios——一个多功能的开发框架

    你是否在开发过程中常常遇到同样的问题,需要不断去寻找解决方案?你是否想要一个多功能、易于使用的开发框架来解决这些问题?那么,Zlios就是你需要的框架。 一、简介 Zlios是一个…

    编程 2025-04-29
  • agavi开发框架

    Agavi是一个基于MVC模式的Web应用程序开发框架,以REST和面向资源的设计为核心思想。本文章将从Agavi的概念、优点、使用方法和实例等方面进行详细介绍。 一、概念 Aga…

    编程 2025-04-29
  • Python unittest框架用法介绍

    Python unittest框架是Python自带的一种测试框架,可以用来编写并运行测试用例。在本文中,我们将从以下几个方面详细介绍Python unittest框架的使用方法和…

    编程 2025-04-29
  • com.alipay.sofa.bolt框架

    com.alipay.sofa.bolt框架是一款高性能、轻量级、可扩展的RPC框架。其广泛被应用于阿里集团内部服务以及阿里云上的服务。该框架通过NIO支持高并发,同时还内置了多种…

    编程 2025-04-29
  • Python最强大的制图库——Matplotlib

    Matplotlib是Python中最强大的数据可视化工具之一,它提供了海量的制图、绘图、绘制动画的功能,通过它可以轻松地展示数据的分布、比较和趋势。下面将从多个方面对Matplo…

    编程 2025-04-29
  • Python range: 强大的迭代器函数

    Python range函数是Python中最常用的内置函数之一。它被广泛用于for循环的迭代,列表推导式,和其他需要生成一系列数字的应用程序中。在本文中,我们将会详细介绍Pyth…

    编程 2025-04-29
  • Django框架:从简介到项目实战

    本文将从Django的介绍,以及如何搭建Django环境开始,逐步深入到Django模型、视图、模板、表单,最后通过一个小型项目实战,进行综合性的应用,让读者获得更深入的学习。 一…

    编程 2025-04-28
  • LuaEP:一款强大的Lua开发框架

    LuaEP是一个集成了可以快速开发web应用程序所需的组件的Lua开发框架。它以Lua语言为基础,提供了许多常用接口和库,使得开发者不需要从头开始编写web应用程序,而是专注于业务…

    编程 2025-04-28
  • Java持久层框架的复合主键实现

    用Java持久层框架来操作数据库时,复合主键是常见的需求。这篇文章将详细阐述javax.persistence复合主键的实现方式,并提供完整的示例代码。 一、复合主键的定义 复合主…

    编程 2025-04-27

发表回复

登录后才能评论