Delphi AOP和DI:如何创建方面感知接口依赖注入对象?

Delphi AOP和DI:如何创建方面感知接口依赖注入对象?,delphi,dependency-injection,aop,spring4d,Delphi,Dependency Injection,Aop,Spring4d,我想通过Spring/4D框架创建一个方面感知的接口依赖注入对象。我的问题是,我不知道如何将这两部分结合起来。总体思路如下: 创建aspect层对象并保留两个接口:一个作为依赖项传递给对象(iSpect),另一个作为aspect嵌入对象(IInterceptor): 创建接口依赖项注入对象: Instance := TInstance.Create(Aspect) {as IInstance}; 在这方面: Result := TProxyGenerator.CreateInterface

我想通过Spring/4D框架创建一个方面感知的接口依赖注入对象。我的问题是,我不知道如何将这两部分结合起来。总体思路如下:

  • 创建aspect层对象并保留两个接口:一个作为依赖项传递给对象(
    iSpect
    ),另一个作为aspect嵌入对象(
    IInterceptor
    ):

  • 创建接口依赖项注入对象:

    Instance := TInstance.Create(Aspect) {as IInstance};
    
  • 在这方面:

    Result := TProxyGenerator.CreateInterfaceProxyWithTarget(Instance, [Interceptor]);
    
  • 为了解决这个问题,我考虑按照以下思路向自定义构造函数注册工厂:

    Aspect := Resolve<IAspect>;
    Interceptor := Aspect as IInterceptor;
    Instance := InstanceFactory(Aspect); // InstanceFactory := Resolve<IInstanceFactory>;
    Result := TProxyGenerator.CreateInterfaceProxyWithTarget(Instance, [Interceptor]);
    
    输出:

    Thingy1.Value: Value 1 intercepted by instance aspect 1 intercepted by class aspect
    Thingy2.Value: Value 2 intercepted by instance aspect 2 intercepted by class aspect
    Press enter...
    

    我不完全确定您到底想要实现什么,但这里介绍了如何设置容器以获得您想要的结果。目前还不起作用的是上下文注入(在解析过程中根据当前构建的对象图做出决策)——这是我们计划在未来实现的

    program Project1;
    
    {$AppType Console}
    
    {$R *.res}
    
    uses
      System.SysUtils,
      Spring,
      Spring.Container,
      Spring.Interception;
    
    type
      IThingy = interface (IInvokable)
        ['{FD337CC6-03EB-4384-A027-E993AB687BF0}']
        function GetValue: String;
        procedure SetValue(const Value: String);
    
        property Value: String read GetValue write SetValue;
      end;
    
      TThingy = class (TInterfacedObject, IThingy)
      strict private
        FValue: String;
    
        function GetValue: String;
        procedure SetValue(const Value: String);
      end;
    
    { TThingy }
    
    function TThingy.GetValue: String;
    begin
      Result := FValue;
    end;
    
    procedure TThingy.SetValue(const Value: String);
    begin
      FValue := Value;
    end;
    
    type
      TClassInterceptor = class(TInterfacedObject, IInterceptor)
        procedure Intercept(const Invocation: IInvocation);
      end;
    
      TInstanceInterceptor = class(TInterfacedObject, IInterceptor)
      private
        class var InstanceCount: Integer;
        var FNo: Integer;
        procedure Intercept(const Invocation: IInvocation);
      public
        constructor Create;
      end;
    
    { Main }
    
    procedure Main;
    var
      Thingy1: IThingy;
      Thingy2: IThingy;
    begin
      GlobalContainer.RegisterType<TClassInterceptor,TClassInterceptor>.AsSingleton;
      GlobalContainer.RegisterType<TInstanceInterceptor>('instance');
      GlobalContainer.RegisterType<IThingy, TThingy>.InterceptedBy<TClassInterceptor>.InterceptedBy('instance');
      GlobalContainer.Build;
    
      Thingy1 := GlobalContainer.Resolve<IThingy>;
      Thingy2 := GlobalContainer.Resolve<IThingy>;
    
      Thingy1.Value := 'Value 1';
      Thingy2.Value := 'Value 2';
    
      WriteLn(Format('Thingy1.Value: %s', [Thingy1.Value]));
      WriteLn(Format('Thingy2.Value: %s', [Thingy2.Value]));
    end;
    
    procedure TClassInterceptor.Intercept(const Invocation: IInvocation);
    begin
      Invocation.Proceed;
    
      if Invocation.Method.Name = 'GetValue' then
        Invocation.Result := TValue.From<String>(Invocation.Result.AsString + ' intercepted by class aspect');
    end;
    
    constructor TInstanceInterceptor.Create;
    begin
      Inc(InstanceCount);
      FNo := InstanceCount;
    end;
    
    procedure TInstanceInterceptor.Intercept(const Invocation: IInvocation);
    begin
      Invocation.Proceed;
    
      if Invocation.Method.Name = 'GetValue' then
        Invocation.Result := TValue.From<String>(Invocation.Result.AsString + ' intercepted by instance aspect ' + IntToStr(FNo));
    end;
    
    begin
      try
        Main;
      except
        on E: Exception do
          WriteLn(E.ClassName, ': ', E.Message);
      end;
      if DebugHook <> 0 then
      begin
        WriteLn('Press enter...');
        ReadLn;
      end;
    end.
    
    程序项目1;
    {$AppType控制台}
    {$R*.res}
    使用
    System.SysUtils,
    春天
    弹簧,容器,
    春天。拦截;
    类型
    i智能=接口(IInvokable)
    [{FD337CC6-03EB-4384-A027-E993AB687BF0}]
    函数GetValue:String;
    过程设置值(常量值:字符串);
    属性值:字符串读取GetValue写入SetValue;
    结束;
    t Thingy=类别(TInterfacedObject,i Thingy)
    严格保密
    FValue:String;
    函数GetValue:String;
    过程设置值(常量值:字符串);
    结束;
    {TThingy}
    函数TThingy.GetValue:字符串;
    开始
    结果:=fv值;
    结束;
    过程TThingy.SetValue(常量值:字符串);
    开始
    FValue:=值;
    结束;
    类型
    TClassInterceptor=类(TInterfacedObject,IIINTERCEPTOR)
    过程截获(const调用:IInvocation);
    结束;
    TInstanceInterceptor=类(TInterfacedObject,IIInterceptor)
    私有的
    类var InstanceCount:整数;
    var-FNo:整数;
    过程截获(const调用:IInvocation);
    公众的
    构造函数创建;
    结束;
    {Main}
    主程序;
    变量
    事情1:我想;
    事情2:我想是的;
    开始
    GlobalContainer.RegisterType.AsSingleton;
    RegisterType('instance');
    GlobalContainer.RegisterType.InterceptedBy.InterceptedBy('instance');
    环球集装箱。建造;
    Thingy1:=全局容器。解析;
    Thingy2:=GlobalContainer.Resolve;
    Thingy1.值:='值1';
    Thingy2.Value:=“值2”;
    WriteLn(格式('Thingy1.Value:%s',[Thingy1.Value]);
    WriteLn(格式('Thingy2.Value:%s',[Thingy2.Value]);
    结束;
    过程tclasinterceptor.Intercept(常量调用:IInvocation);
    开始
    调用。继续;
    如果Invocation.Method.Name='GetValue',则
    Invocation.Result:=TValue.From(Invocation.Result.AsString+‘被类方面截获’);
    结束;
    构造函数TInstanceInterceptor.Create;
    开始
    公司(InstanceCount);
    FNo:=实例计数;
    结束;
    过程TInstanceInterceptor.Intercept(常量调用:IInvocation);
    开始
    调用。继续;
    如果Invocation.Method.Name='GetValue',则
    Invocation.Result:=TValue.From(Invocation.Result.AsString+'被实例方面截获'+IntToStr(FNo));
    结束;
    开始
    尝试
    主要的;
    除了
    关于E:Exception-do
    WriteLn(E.ClassName,“:”,E.Message);
    结束;
    如果为0,则
    开始
    WriteLn('按enter…');
    ReadLn;
    结束;
    结束。
    
    Thingy1.Value: Value 1 intercepted by instance aspect 1 intercepted by class aspect
    Thingy2.Value: Value 2 intercepted by instance aspect 2 intercepted by class aspect
    Press enter...
    
    program Project1;
    
    {$AppType Console}
    
    {$R *.res}
    
    uses
      System.SysUtils,
      Spring,
      Spring.Container,
      Spring.Interception;
    
    type
      IThingy = interface (IInvokable)
        ['{FD337CC6-03EB-4384-A027-E993AB687BF0}']
        function GetValue: String;
        procedure SetValue(const Value: String);
    
        property Value: String read GetValue write SetValue;
      end;
    
      TThingy = class (TInterfacedObject, IThingy)
      strict private
        FValue: String;
    
        function GetValue: String;
        procedure SetValue(const Value: String);
      end;
    
    { TThingy }
    
    function TThingy.GetValue: String;
    begin
      Result := FValue;
    end;
    
    procedure TThingy.SetValue(const Value: String);
    begin
      FValue := Value;
    end;
    
    type
      TClassInterceptor = class(TInterfacedObject, IInterceptor)
        procedure Intercept(const Invocation: IInvocation);
      end;
    
      TInstanceInterceptor = class(TInterfacedObject, IInterceptor)
      private
        class var InstanceCount: Integer;
        var FNo: Integer;
        procedure Intercept(const Invocation: IInvocation);
      public
        constructor Create;
      end;
    
    { Main }
    
    procedure Main;
    var
      Thingy1: IThingy;
      Thingy2: IThingy;
    begin
      GlobalContainer.RegisterType<TClassInterceptor,TClassInterceptor>.AsSingleton;
      GlobalContainer.RegisterType<TInstanceInterceptor>('instance');
      GlobalContainer.RegisterType<IThingy, TThingy>.InterceptedBy<TClassInterceptor>.InterceptedBy('instance');
      GlobalContainer.Build;
    
      Thingy1 := GlobalContainer.Resolve<IThingy>;
      Thingy2 := GlobalContainer.Resolve<IThingy>;
    
      Thingy1.Value := 'Value 1';
      Thingy2.Value := 'Value 2';
    
      WriteLn(Format('Thingy1.Value: %s', [Thingy1.Value]));
      WriteLn(Format('Thingy2.Value: %s', [Thingy2.Value]));
    end;
    
    procedure TClassInterceptor.Intercept(const Invocation: IInvocation);
    begin
      Invocation.Proceed;
    
      if Invocation.Method.Name = 'GetValue' then
        Invocation.Result := TValue.From<String>(Invocation.Result.AsString + ' intercepted by class aspect');
    end;
    
    constructor TInstanceInterceptor.Create;
    begin
      Inc(InstanceCount);
      FNo := InstanceCount;
    end;
    
    procedure TInstanceInterceptor.Intercept(const Invocation: IInvocation);
    begin
      Invocation.Proceed;
    
      if Invocation.Method.Name = 'GetValue' then
        Invocation.Result := TValue.From<String>(Invocation.Result.AsString + ' intercepted by instance aspect ' + IntToStr(FNo));
    end;
    
    begin
      try
        Main;
      except
        on E: Exception do
          WriteLn(E.ClassName, ': ', E.Message);
      end;
      if DebugHook <> 0 then
      begin
        WriteLn('Press enter...');
        ReadLn;
      end;
    end.