using System;
using System.Collections.Generic;
using UnityEngine;
public class IOCContainer
{
//创建字典存储实例
private Dictionary<Type, object> m_instances = new Dictionary<Type, object>();
public void RegisterInstance<T>(T instance)
{
//反射获取类信息
var type = typeof(T);
//判断是否存在
if (m_instances.ContainsKey(type))
{ //如果存在,则替换
m_instances[type] = instance;
}
else
{ //不存在,则添加
m_instances.Add(type, instance);
}
}
public T Get<T>() where T : class
{ //获取实例
var key = typeof(T);
//out 存储
object retInstance;
//判断是否存在
if (m_instances.TryGetValue(key,out retInstance))
{
//存在,则直接返回
return retInstance as T;
}
//不存在 抛出异常
Debug.LogError("IOCContainer:未包括实例" + typeof(T).Name);
return null;
}
}
===============================================================================
using UnityEngine;
public abstract class Architecture<T> where T : Architecture<T>, new()
{
public static T mArchitecture;
// 确保 Container 是有实例的
static void MakesureArchitecture()
{
if (mArchitecture == null)
{
mArchitecture = new T();
mArchitecture.Init();
}
}
//留给子类注册模块
protected abstract void Init();
// 提供一个注册模块的 API
public void Register<T>(T instance)
{
MakesureArchitecture();
mArchitecture.mIOCContainer.RegisterInstance<T>(instance);//注册进IOC容器
}
private IOCContainer mIOCContainer = new IOCContainer();
// 提供一个获取模块的 API
public static T Get<T>() where T : class
{
MakesureArchitecture();
return mArchitecture.mIOCContainer.Get<T>();//从IOC容器获取实例
}
}
=====================================================================================
这里我们创建一个 DIPExample.cs 脚本,DIP 是依赖倒置原则的意思,代码如下:
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
public class DIPExample : MonoBehaviour
{
// 1. 设计模块接口
public interface IStorage
{
void SaveString(string key, string value);
string LoadString(string key, string defaultValue = "");
}
// 2. 实现接口
// 运行时存储
public class PlayerPrefsStorage : IStorage
{
public void SaveString(string key, string value)
{
PlayerPrefs.SetString(key, value);
}
public string LoadString(string key, string defaultValue = "")
{
return PlayerPrefs.GetString(key, defaultValue);
}
}
// 3. 实现接口
// 编辑器存储
public class EditorPrefsStorage : IStorage
{
public void SaveString(string key, string value)
{
#if UNITY_EDITOR
EditorPrefs.SetString(key, value);
#endif
}
public string LoadString(string key, string defaultValue = "")
{
#if UNITY_EDITOR
return EditorPrefs.GetString(key, defaultValue);
#else
return ""
#endif
}
}
// 4. 使用
private void Start()
{
// 创建一个 IOC 容器
var container = new IOCContainer();
// 注册运行时模块
container.Register<IStorage>(new PlayerPrefsStorage());
var storage = container.Get<IStorage>();
storage.SaveString("name", "运行时存储");
Debug.Log(storage.LoadString("name"));
// 切换实现
container.Register<IStorage>(new EditorPrefsStorage());
storage = container.Get<IStorage>();
Debug.Log(storage.LoadString("name"));
}
}
}
不管是模块的设计过程,还是切换实现,还是解耦这个示例都有所体现。
======================================================================================
还可以增加单个容器保存多个接口
public class IOCContainer
{
// 使用 Dictionary 存储接口到其实现列表的映射
private readonly Dictionary<Type, List<(string, object)> mInstances = new Dictionary<Type, List<(string, object)>>();
public void Register<T>(string name, T instance) where T : class
{
if (!mInstances.ContainsKey(typeof(T)))
{
mInstances[typeof(T)] = new List<(string, object)>();
}
mInstances[typeof(T)].Add((name, instance));
}
public T Get<T>(string name) where T : class
{
if (mInstances.TryGetValue(typeof(T), out var instances))
{
foreach (var (n, instance) in instances)
{
if (n == name)
return instance as T;
}
}
//不存在 抛出异常
Debug.LogError("IOCContainer:未包括实例" + typeof(T).Name);
return null;
}
}
=====================================================================================
container.Register<IGameManager>("V1", new SoundManagerV1());
container.Register<IGameManager>("V2", new SoundManagerV2());
var v1Manager = container.Get<IGameManager>("V1");
v1Manager.Connect(); // 连接,这里假设V1的实现会打印"V1连接成功"
var v2Manager = container.Get<IGameManager>("V2");
v2Manager.Connect(); // 连接,这里假设V2的实现会打印"V2连接成功"
IOC容器代码设计 4
最新推荐文章于 2024-09-17 08:07:57 发布