2016-06-09 25 views
2

我想通过Spring/4D框架的方式创建一个方面感知的接口依赖注入对象。我的问题是,我不知道如何组合这两个部分。总的想法是:AOP和DI:如何创建一个方面感知接口的依赖注入对象?

  1. 创建方面层对象和保持两个接口到它:一个通过作为依赖于所述对象(IAspect)和一个编织在作为一方面到物体(IInterceptor ):

    Temp := TAspect.Create; 
    Aspect := Temp as IAspect; 
    Interceptor := Temp as IInterceptor; 
    
  2. 创建接口依赖注入对象:

    Instance := TInstance.Create(Aspect) {as IInstance}; 
    
  3. 编织在看点:

    Result := TProxyGenerator.CreateInterfaceProxyWithTarget(Instance, [Interceptor]); 
    

为了解决这个问题,我想沿着这些线路自定义构造函数注册的工厂:

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

我的问题是,我怎么会用Container: TContainer从登记本弹簧?


:下面的程序的行为类似于我想和通过其方面层GetValue呼叫运行演示。自定义对象的创建在主程序中有$Region。我将如何重构此程序以使用Spring/4D框架中的DI容器,但是保留一个方面感知对象的自定义构造?

program Project1; 

{$AppType Console} 

{$R *.res} 

uses 
    System.SysUtils, 
    Spring, 
    Spring.Interception; 

type 
    IAspect = interface 
    ['{AF8E19F6-176D-490E-A475-4682336CAB89}'] 
    function GetSetting: String; 
    procedure SetSetting(const Value: String); 

    property Setting: String read GetSetting write SetSetting; 
    end; 

    TAspect = class (TInterfacedObject, IInterceptor, IAspect) 
    strict private 
    FSetting: String; 

    function GetSetting: String; 
    procedure SetSetting(const Value: String); 

    procedure Intercept(const Invocation: IInvocation); 

    public 
    constructor Create; 
    end; 

    IThingy = interface (IInvokable) 
    function GetAspect: IAspect; 
    function GetValue: String; 
    procedure SetValue(const Value: String); 

    property InstanceAspect: IAspect read GetAspect; 
    property Value: String read GetValue write SetValue; 
    end; 

    TThingy = class (TInterfacedObject, IThingy) 
    strict private 
    FInstanceAspect: IAspect; 
    FClassAspect: IAspect; 
    FValue: String; 

    function GetAspect: IAspect; 
    function GetValue: String; 
    procedure SetValue(const Value: String); 

    public 
    constructor Create(const InstanceAspect, ClassAspect: IAspect); 
    end; 

{ TAspect } 

constructor TAspect.Create; 
begin 
    inherited; 
    FSetting := ' intercepted by class aspect'; 
end; 

function TAspect.GetSetting: String; 
begin 
    Result := FSetting; 
end; 

procedure TAspect.Intercept(
    const Invocation: IInvocation); 
begin 
    Invocation.Proceed; 

    if Invocation.Method.Name = 'GetValue' then 
    Invocation.Result := TValue.From<String>(Invocation.Result.AsString + FSetting); 
end; 

procedure TAspect.SetSetting(
    const Value: String); 
begin 
    FSetting := Value; 
end; 

{ TThingy } 

constructor TThingy.Create(const InstanceAspect, ClassAspect: IAspect); 
begin 
    inherited Create; 
    FInstanceAspect := InstanceAspect; 
    FClassAspect := ClassAspect; 
    FValue := 'Value'; 
end; 

function TThingy.GetAspect: IAspect; 
begin 
    Result := FInstanceAspect; 
end; 

function TThingy.GetValue: String; 
begin 
    Result := FValue; 
end; 

procedure TThingy.SetValue(const Value: String); 
begin 
    FValue := Value; 
end; 

{ Main } 

procedure Main; 
var 
    Temp: TInterfacedObject; 
    ClassAspect: IAspect; 
    ClassInterceptor: IInterceptor; 
    InstanceAspect: IAspect; 
    InstanceInterceptor: IInterceptor; 
    Thingy1: IThingy; 
    Thingy2: IThingy; 
begin 
    {$Region 'How to do this with the Spring DI container?'} 
    Temp := TAspect.Create; 
    ClassAspect := Temp as IAspect; 
    ClassInterceptor := Temp as IInterceptor; 

    Temp := TAspect.Create; 
    InstanceAspect := Temp as IAspect; 
    InstanceInterceptor := Temp as IInterceptor; 
    Thingy1 := TThingy.Create(InstanceAspect, ClassAspect); 
    Thingy1 := TProxyGenerator.CreateInterfaceProxyWithTarget(Thingy1, [ClassInterceptor, InstanceInterceptor]); 

    Temp := TAspect.Create; 
    InstanceAspect := Temp as IAspect; 
    InstanceInterceptor := Temp as IInterceptor; 
    Thingy2 := TThingy.Create(InstanceAspect, ClassAspect); 
    Thingy2 := TProxyGenerator.CreateInterfaceProxyWithTarget(Thingy2, [ClassInterceptor, InstanceInterceptor]); 
    {$EndRegion} 

    Thingy1.InstanceAspect.Setting := ' intercepted by instance aspect 1'; 
    Thingy2.InstanceAspect.Setting := ' intercepted by instance aspect 2'; 

    Thingy1.Value := 'Value 1'; 
    Thingy2.Value := 'Value 2'; 

    WriteLn(Format('Thingy1.Value: %s', [Thingy1.Value])); 
    WriteLn(Format('Thingy2.Value: %s', [Thingy2.Value])); 
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. 

输出:

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... 

回答

2

我不能完全肯定究竟你要实现的目标,但在这里它如何设置容器,让你正在寻找的结果。还没有工作的是上下文注入(在决策过程中根据当前构建的对象图做出决策) - 这是我们计划在未来实现的。

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.