TInterfaceResolver&TInjectableObject

TInterfaceResolver&TInjectableObject

{ ************ TInterfaceResolver TInjectableObject 用于控制反转(IoC)/依赖注入(Dependency Injection) }

type
  /// 在依赖注入(又名IoC)问题发生时抛出的异常
  EInterfaceResolver = class(ESynException);

  {$M+}
  /// 抽象工厂类,允许以级联方式调用接口解析
  // - 你可以从此类继承以链式调用TryResolve()方法,
  // 这样TInjectableObject就可以询问多种实现,
  // 例如TInterfaceStub、TServiceContainer或TDDDRepositoryRestObjectMapping
  // - 这将实现工厂模式,作为一个安全且线程安全的依赖注入/控制反转实现
  TInterfaceResolver = class
  protected
    /// 从此实例解析接口的重写方法
    function TryResolve(aInterface: PRttiInfo; out Obj): boolean; virtual; abstract;
  public
    /// 重写此方法以检查此实例是否实现了aInterface RTTI
    // - 此默认实现将在本地IInterface上调用TryResolve(),
    // 这有些慢,最好重写此方法
    function Implements(aInterface: PRttiInfo): boolean; virtual;
    /// 可用于对给定接口执行依赖注入/控制反转
    // - 将在其内部解析器列表中搜索提供的接口
    // - 如果找到匹配项,则返回TRUE并设置Obj变量
    // - 可以这样使用来解析ICalculator接口:
    // ! var calc: ICalculator;
    // ! begin
    // !   if Catalog.Resolve(TypeInfo(ICalculator),calc) then
    // !   ... 使用calc方法
    function Resolve(aInterface: PRttiInfo; out Obj): boolean; overload;
    /// 可用于对给定接口执行依赖注入/控制反转
    // - 你应该通过之前调用TInterfaceFactory.RegisterInterfaces([TypeInfo(ICalculator),...])来注册TGuid接口
    // - 如果找到匹配项,则返回TRUE并设置Obj变量
    // - 如果aGuid不可用,则返回FALSE(或抛出aRaiseIfNotFound异常)
    // - 可以这样使用来解析ICalculator接口:
    // ! var calc: ICalculator;
    // ! begin
    // !   if ServiceContainer.Resolve(ICalculator,cal) then
    // !   ... 使用calc方法
    function Resolve(const aGuid: TGuid; out Obj;
      aRaiseIfNotFound: ESynExceptionClass = nil): boolean; overload;
    /// 可用于对给定的一组接口执行多个依赖注入/控制反转
    // - 这里的接口和实例作为TypeInfo,@Instance对提供
    // - 如果有任何接口无法解析,则抛出EServiceException,除非
    // aRaiseExceptionIfNotFound设置为FALSE
    procedure ResolveByPair(const aInterfaceObjPairs: array of pointer;
      aRaiseExceptionIfNotFound: boolean = true);
    /// 可用于对给定的一组接口执行多个依赖注入/控制反转
    // - 这里的接口和实例作为TGuid和@Instance提供
    // - 你应该通过之前调用TInterfaceFactory.RegisterInterfaces([TypeInfo(ICalculator),...])来注册TGuid接口
    // - 如果有任何接口无法解析,则抛出EServiceException,除非
    // aRaiseExceptionIfNotFound设置为FALSE
    procedure Resolve(const aInterfaces: array of TGuid;
                      const aObjs: array of pointer;
      aRaiseExceptionIfNotFound: boolean = true); overload;
  end;
  {$M-}

  /// 用于存储TInterfacedObject实例的列表
  TInterfacedObjectObjArray = array of TInterfacedObject;

  /// 用于存储TInterfaceResolver实例的列表
  TInterfaceResolverObjArray = array of TInterfaceResolver;

  /// 抽象工厂类,针对单一类型的接口
  TInterfaceResolverForSingleInterface = class(TInterfaceResolver)
  protected
    fInterfaceTypeInfo: PRttiInfo;
    fInterfaceAncestors: PRttiInfoDynArray;
    fInterfaceAncestorsImplementationEntry: TPointerDynArray;
    fImplementationEntry: PInterfaceEntry;
    fImplementation: TRttiCustom;
    function TryResolve(aInterface: PRttiInfo; out Obj): boolean; override;
    function GetImplementationName: RawUtf8;
    // 主要的IoC/DI虚拟方法 - 默认情况下调用fImplementation.CreateNew
    function CreateInstance: TInterfacedObject; virtual;
  public
    /// 重写的构造函数,用于检查和存储提供的类以实现接口
    constructor Create(aInterface: PRttiInfo;
      aImplementation: TInterfacedObjectClass); overload;
    /// 重写的构造函数,用于通过TGuid检查和存储提供的类以实现接口
    constructor Create(const aInterface: TGuid;
      aImplementation: TInterfacedObjectClass); overload;
    /// 使用此方法可以将接口解析为新实例
    function GetOneInstance(out Obj): boolean;
    /// 检查是否可以解析提供的接口RTTI
    function Implements(aInterface: PRttiInfo): boolean; override;
  published
    /// 实现每个存储库实例的类名
    property ImplementationClass: RawUtf8
      read GetImplementationName;
  end;

type
  /// TInterfaceResolverList如何存储一个接口/类
  TInterfaceResolverListEntry = record
    /// 包含TypeInfo(ISomeInterface)
    TypeInfo: PRttiInfo;
    /// 相关的RTTI - 主要用于调用其ClassNewInstance方法
    ImplementationClass: TRttiCustom;
    /// 用于快速创建的低级接口VMT信息
    InterfaceEntry: PInterfaceEntry;
    /// 共享实例
    // - 将与TInterfaceResolverListEntries数组一起释放
    Instance: IInterface;
  end;
  PInterfaceResolverListEntry = ^TInterfaceResolverListEntry;

  /// TInterfaceResolverList如何存储一个接口/类
  TInterfaceResolverListEntries = array of TInterfaceResolverListEntry;

  /// TInterfaceResolverList.OnCreateInstance使用的事件签名
  TOnResolverCreateInstance = procedure(
    Sender: TInterfaceResolver; Instance: TInterfacedObject) of object;

  /// 注册一个线程安全的类列表以实现一些接口
  // - 如TInterfaceResolverInjected.RegisterGlobal()所用
  TInterfaceResolverList = class(TInterfaceResolver)
  protected
    fEntry: TInterfaceResolverListEntries;
    fSafe: TRWLightLock;
    fOnCreateInstance: TOnResolverCreateInstance;
    function PrepareAddAndWriteLock(aInterface: PRttiInfo;
      aImplementationClass: TClass): PInterfaceEntry; // 之后解锁fSafe.WriteUnLock
    function TryResolve(aInterface: PRttiInfo; out Obj): boolean; override;
  public
    /// 检查是否可以从其RTTI解析给定的接口
    function Implements(aInterface: PRttiInfo): boolean; override;
    /// 为接口注册一个给定的实现类
    // - 每次解析都会为aImplementationClass创建一个新实例
    procedure Add(aInterface: PRttiInfo;
      aImplementationClass: TInterfacedObjectClass); overload;
    /// 为接口注册一个给定的实现类实例
    // - 每次解析都会返回共享的aImplementation实例
    // - aImplementation将由内部注册列表管理
    procedure Add(aInterface: PRttiInfo;
      aImplementation: TInterfacedObject); overload;
    /// 注销接口的给定实现类
    // - 如果注册了TInterfacedObject实例,则引发EInterfaceResolver
    procedure Delete(aInterface: PRttiInfo);
    /// 当创建了新的aImplementationClass实例时调用
    property OnCreateInstance: TOnResolverCreateInstance
      read fOnCreateInstance write fOnCreateInstance;
    /// 低级访问内部注册的接口/类列表
    // - 应通过Safe锁定方法进行保护
    property Entry: TInterfaceResolverListEntries
      read fEntry;
    /// 低级访问内部锁以实现线程安全
    property Safe: TRWLightLock
      read fSafe;
  end;  

/// 针对任意接口的抽象工厂类
// - 你可以从这个类继承来自定义依赖注入(DI/IoC),
// 通过InjectStub/InjectResolver/InjectInstance方法定义解析,
// 并使用重载的Resolve*()方法来完成实例解析
// - TServiceContainer将继承自此类,作为框架中基于接口的服务的主要入口点(通过TRest.Services)
// - 你可以使用RegisterGlobal()类方法来定义一些进程范围的DI
TInterfaceResolverInjected = class(TInterfaceResolver)
protected
    fResolvers: TInterfaceResolverObjArray;
    fResolversToBeReleased: TInterfaceResolverObjArray;
    fDependencies: TInterfacedObjectObjArray;
    function TryResolve(aInterface: PRttiInfo; out Obj): boolean; override;
public
    /// 为接口解析定义一个全局类类型
    // - 大多数情况下,你需要一个本地的DI/IoC解析列表;但
    // 你可以使用此方法注册一组共享和全局的解析模式,这些模式在整个注入过程中是通用的
    // - 默认情况下,此单元将注册TAutoLocker和TLockedDocVariant以实现IAutoLocker和ILockedDocVariant接口
    class procedure RegisterGlobal(aInterface: PRttiInfo;
      aImplementationClass: TInterfacedObjectClass); overload;
    /// 为接口解析定义一个全局实例
    // - 大多数情况下,你需要一个本地的DI/IoC解析列表;但
    // 你可以使用此方法注册一组共享和全局的解析模式,这些模式在整个注入过程中是通用的
    // - 提供的实例将由全局列表拥有(增加其内部引用计数),
    // 直到通过RegisterGlobalDelete()释放
    // - 如果之前未通过RegisterGlobalDelete()释放,则在单元的最终化过程中释放提供的实例
    class procedure RegisterGlobal(aInterface: PRttiInfo;
      aImplementation: TInterfacedObject); overload;
    /// 取消定义一个全局接口解析实例
    // - 你可以注销之前通过RegisterGlobal(aInterface,aImplementation)定义的给定实例
    // - 如果你没有调用RegisterGlobalDelete(),则剩余实例将在单元的最终化过程中被释放
    class procedure RegisterGlobalDelete(aInterface: PRttiInfo);
    /// 准备并设置接口DI/IoC解析,使用其TGuid指定的空TInterfaceStub
    procedure InjectStub(const aStubsByGuid: array of TGuid); overload; virtual;
    /// 准备并设置接口DI/IoC解析,使用TInterfaceResolver类型的工厂
    // - 例如,自定义的TInterfaceStub/TInterfaceMock,TServiceContainer,
    // TDDDRepositoryRestObjectMapping或任何工厂类
    // - 默认情况下,只有TInterfaceStub/TInterfaceMock将由此实例拥有,并在Destroy时释放
    // - 除非设置了OwnOtherResolvers,否则其他解析器不会被释放
    procedure InjectResolver(const aOtherResolvers: array of TInterfaceResolver;
      OwnOtherResolvers: boolean = false); overload; virtual;
    /// 从TInterfacedObject实例准备并设置接口DI/IoC解析
    // - 声明为依赖项的任何TInterfacedObject的引用计数将增加,并在Destroy时减少
    procedure InjectInstance(const aDependencies: array of TInterfacedObject);
      overload; virtual;
    /// 检查给定的接口是否可以通过其RTTI解析
    function Implements(aInterface: PRttiInfo): boolean; override;
    /// 删除之前注册的解析器
    // - 之后可以重新注册aResolver
    procedure DeleteResolver(aResolver: TInterfaceResolver);
    /// 释放所有已使用的实例
    // - 包括Inject(aStubsByGuid)中指定的所有TInterfaceStub实例
    // - 将在所有TInterfacedObject依赖项上调用_Release
    destructor Destroy; override;
end;

/// 任何服务实现类都可以继承自此类,以允许框架进行依赖注入(也称为SOLID DI/IoC)
// - 创建后,框架将调用AddResolver()成员,以便其Resolve*()方法可用于注入任何所需的依赖项以进行延迟依赖项解析(例如,在公共属性getter中)
// - 发布的任何接口属性也将自动注入
// - 如果你使用此类实现了SOA服务,则TRestServer.Services将通过TServiceFactoryServer.CreateInstance()自动注入
TInjectableObject = class(TInterfacedObjectWithCustomCreate)
protected
    fResolver: TInterfaceResolver;
    fResolverOwned: boolean;
    fRtti: TRttiCustom;
    // DI/IoC解析受保护的方法
    function TryResolve(aInterface: PRttiInfo; out Obj): boolean;
    /// 此方法将解析所有接口发布的属性
    procedure AutoResolve(aRaiseEServiceExceptionIfNotFound: boolean);
public
    /// 初始化实例,定义一个或多个依赖项解析方式
    // - 可以直接从其TGuid创建简单的TInterfaceStub,
    // 然后可以指定任何类型的DI/IoC解析器实例,即
    // 自定义的TInterfaceStub/TInterfaceMock,TServiceContainer或
    // TDDDRepositoryRestObjectMapping,然后在依赖项解析期间将使用任何TInterfacedObject实例:
    // ! procedure TMyTestCase.OneTestCaseMethod;
    // ! var Test: IServiceToBeTested;
    // ! begin
    // !   Test := TServiceToBeTested.CreateInjected(
    // !     [ICalculator],
    // !     [TInterfaceMock.Create(IPersistence,self).
    // !       ExpectsCount('SaveItem',qoEqualTo,1),
    // !      RestInstance.Services],
    // !     [AnyInterfacedObject]);
    // !   ...
    // - 请注意,所有注入的存根/模拟实例都将由TInjectableObject拥有,并在释放时一起释放
    // - 声明为依赖项的任何TInterfacedObject的引用计数将增加,并在Destroy时减少
    // - 定义DI/IoC后,将调用受保护的AutoResolve()方法
    constructor CreateInjected(const aStubsByGuid: array of TGuid;
      const aOtherResolvers: array of TInterfaceResolver;
      const aDependencies: array of TInterfacedObject;
      aRaiseEServiceExceptionIfNotFound: boolean = true); virtual;
    /// 初始化实例,定义一个依赖项解析器
    // - 解析器可能是例如TServiceContainer
    // - 定义DI/IoC后,将调用受保护的AutoResolve()方法
    // - 如TServiceFactoryServer.CreateInstance所调用
    constructor CreateWithResolver(aResolver: TInterfaceResolver;
      aRaiseEServiceExceptionIfNotFound: boolean = true); virtual;
    /// 可用于对给定接口类型信息进行DI/IoC
    procedure Resolve(aInterface: PRttiInfo; out Obj); overload;
    /// 可用于对给定接口TGuid进行DI/IoC
    procedure Resolve(const aGuid: TGuid; out Obj); overload;
    /// 可用于对给定的一组接口执行多个DI/IoC
    // - 此处接口和实例作为TypeInfo,@Instance对提供
    procedure ResolveByPair(const aInterfaceObjPairs: array of pointer);
    /// 可用于对给定的一组接口执行多个DI/IoC
    // - 此处接口和实例作为TGuid和指针提供
    procedure Resolve(const aInterfaces: array of TGuid;
      const aObjs: array of pointer); overload;
    /// 释放所有已使用的实例
    // - 包括CreateInjected()中指定的所有TInterfaceStub实例
    destructor Destroy; override;
    /// 访问关联的依赖项解析器(如果有)
    property Resolver: TInterfaceResolver
      read fResolver;
end;

/// TInjectableObject类型的类引用类型(元类)
TInjectableObjectClass = class of TInjectableObject;

var
  /// 全局线程安全列表,用于进程范围内的接口解析
  // - TInterfaceResolverInjected.RegisterGlobal/RegisterGlobalDelete
  // 类方法重定向到GlobalInterfaceResolver.Add/Delete
  // - 本单元的初始化部分将在启动时执行:
  // ! GlobalInterfaceResolver.Add(TypeInfo(IAutoLocker), TAutoLocker);
  // ! GlobalInterfaceResolver.Add(TypeInfo(ILockedDocVariant), TLockedDocVariant);
  GlobalInterfaceResolver: TInterfaceResolverList;
posted @ 2024-07-25 22:59  海利鸟  阅读(29)  评论(0编辑  收藏  举报