Continuar de cima
O contêiner IOC é uma ferramenta de gerenciamento de módulo muito conveniente.
Além de serem utilizados para registrar e obter módulos, os contêineres IOC geralmente possuem uma função oculta, a saber:
Registrar módulo de interface
Abstração - A forma como esta forma de registro e recuperação de objetos é implementada é consistente com o princípio de inversão de dependências .
Princípio de Inversão de Dependência: Os programas devem depender de interfaces abstratas, não de implementações concretas.
Os benefícios são os seguintes:
- O design e a implementação da interface são divididos em duas etapas: ao projetar a interface, você pode se concentrar no design e, ao implementá-la, pode se concentrar na implementação.
- Concentrar-se no design ao projetar a interface pode reduzir a interferência durante o projeto do sistema.
- A implementação pode ser substituída. Por exemplo, se uma interface for chamada IStorage, sua implementação pode ser PlayerPrefsStorage, EasySaveStorage ou EdtiroPrefsStorage. Ao alternar, apenas uma linha de código é necessária para alternar.
- Mais fácil de testar (testes de unidade, etc.)
- Quando os detalhes da implementação (como PlayerPrefsStorage) mudam, o código em sua classe de interface de referência (como IStorage) não muda de acordo, reduzindo o acoplamento.
- etc.
Suporte para armazenamento de dados
Tecnologia de castração de interface
A implementação explícita da interface C# é usada para atingir o objetivo de castrar o método de interface na subclasse. Se você quiser chamar esse método, deverá passar a interface em vez do objeto onde o método está localizado.
using UnityEngine;
namespace FrameworkDesign.Example
{
/// <summary>
/// 1. 定义接口
/// </summary>
public interface ICanSayHello
{
void SayHello();
void SayOther();
}
public class InterfaceDesignExample : MonoBehaviour,ICanSayHello
{
/// <summary>
/// 接口的隐式实现
/// </summary>
public void SayHello()
{
Debug.Log("Hello");
}
/// <summary>
/// 接口的显式实现
/// </summary>
void ICanSayHello.SayOther()
{
Debug.Log("Other");
}
// Start is called before the first frame update
void Start()
{
// 隐式实现的方法可以直接通过对象调用
this.SayHello();
// 显式实现的接口不能通过对象调用
// this.SayOther() // 会报编译错误
// 显式实现的接口必须通过接口对象调用
(this as ICanSayHello).SayOther();
}
}
}
// Métodos explicitamente implementados devem ser chamados através do objeto de interface
( isto como ICanSayHello ) .SayOther ();
Se você quiser chamar um método explicitamente implementado de um objeto, você deve converter o objeto em um objeto de interface antes de chamá-lo. Isso aumenta o custo de chamar o método explicitamente implementado, para que possa ser entendido que este método foi castrado.
Caso de uso 1 estrutura de classe de implementação de classe abstrata de interface
第一种就是比较常见的 接口-抽象类-实现类的结构,示例代码如下:
using UnityEngine;
namespace FrameworkDesign.Example
{
public class InterfaceStructExample : MonoBehaviour
{
/// <summary>
/// 接口
/// </summary>
public interface ICustomScript
{
void Start();
void Update();
void Destroy();
}
/// <summary>
/// 抽象类
/// </summary>
public abstract class CustomScript : ICustomScript
{
protected bool mStarted { get; private set; }
protected bool mDestroyed { get; private set; }
/// <summary>
/// 不希望子类访问 Start 方法,因为有可能破坏状态
/// </summary>
void ICustomScript.Start()
{
OnStart();
mStarted = true;
}
void ICustomScript.Update()
{
OnUpdate();
}
void ICustomScript.Destroy()
{
OnDestroy();
mDestroyed = true;
}
/// <summary>
/// 希望子类实现 OnStart 方法
/// </summary>
protected abstract void OnStart();
protected abstract void OnUpdate();
protected abstract void OnDestroy();
}
/// <summary>
/// 由用户扩展的类
/// </summary>
public class MyScript : CustomScript
{
protected override void OnStart()
{
Debug.Log("MyScript:OnStart");
}
protected override void OnUpdate()
{
Debug.Log("MyScript:OnUpdate");
}
protected override void OnDestroy()
{
Debug.Log("MyScript:OnDestroy");
}
}
/// <summary>
/// 测试脚本
/// </summary>
private void Start()
{
ICustomScript script = new MyScript();
script.Start();
script.Update();
script.Destroy();
}
}
}
Interface do segundo caso de uso + regras de acesso para restringir métodos ao estender
using UnityEngine;
namespace FrameworkDesign.Example
{
public class CanDoEveryThing
{
public void DoSomething1()
{
Debug.Log("DoSomething1");
}
public void DoSomething2()
{
Debug.Log("DoSomething2");
}
public void DoSomething3()
{
Debug.Log("DoSomething3");
}
}
public interface IHasEveryThing
{
CanDoEveryThing CanDoEveryThing { get; }
}
public interface ICanDoSomething1 : IHasEveryThing
{
}
public static class ICanDoSomeThing1Extensions
{
public static void DoSomething1(this ICanDoSomething1 self)
{
self.CanDoEveryThing.DoSomething1();
}
}
public interface ICanDoSomething2 : IHasEveryThing
{
}
public static class ICanDoSomeThing2Extensions
{
public static void DoSomething2(this ICanDoSomething2 self)
{
self.CanDoEveryThing.DoSomething2();
}
}
public interface ICanDoSomething3 : IHasEveryThing
{
}
public static class ICanDoSomeThing3Extensions
{
public static void DoSomething3(this ICanDoSomething3 self)
{
self.CanDoEveryThing.DoSomething3();
}
}
public class InterfaceRuleExample : MonoBehaviour
{
public class OnlyCanDo1 : ICanDoSomething1
{
CanDoEveryThing IHasEveryThing.CanDoEveryThing { get; } = new CanDoEveryThing();
}
public class OnlyCanDo23 : ICanDoSomething2,ICanDoSomething3
{
CanDoEveryThing IHasEveryThing.CanDoEveryThing { get; } = new CanDoEveryThing();
}
private void Start()
{
var onlyCanDo1 = new OnlyCanDo1();
// 可以调用 DoSomething1
onlyCanDo1.DoSomething1();
// 不能调用 DoSomething2 和 3 会报编译错误
// onlyCanDo1.DoSomething2();
// onlyCanDo1.DoSomething3();
var onlyCanDo23 = new OnlyCanDo23();
// 不可以调用 DoSomething1 会报编译错误
// onlyCanDo23.DoSomething1();
// 可以调用 DoSomething2 和 3
onlyCanDo23.DoSomething2();
onlyCanDo23.DoSomething3();
}
}
}
para concluir:
- O conhecimento central da tecnologia de castração de interface é a implementação explícita da interface
- Ao usar interface + classe abstrata + classe concreta, você pode usar a tecnologia de castração de interface se não quiser que alguns métodos sejam chamados aleatoriamente.
- Ao usar interface + extensão estática, você pode usar a tecnologia de castração de interface quando quiser obter acesso a métodos específicos implementando uma interface.