如何避免重复转换为后代接口类型?

时间:2011-10-18 03:38:16

标签: delphi frameworks

我正在制作一个框架(仅供内部使用),该框架在3 o 4个delphi数据库CRUD应用程序中具有通用代码。

mi框架的一个共同目标是TContext,

TContext = class (IContext)
  function DB: IDatabase;
  function CurrentSettings: ISettings;
  ..
 end;

传递给许多其他对象的初始化方法。例子(这将是应用程序代码):

 TCustomer.Initialize(Context: IContext)
 TProjectList.Initialize(Context: IContext)
 ..

每个应用程序都有一些特定的上下文函数(只能从应用程序代码中调用):

 IApp1Context = interface (IContext)
   procedure DoSomethingSpecificToApp1;
   procedure DoOtherThing;
   ..
 end;

所以当我创建一个Context时,我创建一个IApp1Context,然后将它发送到初始化方法..从框架代码一切都很好,问题是从应用程序代码我经常从IContext转到IApp1Context到访问具体 App1函数..所以我的应用程序代码看起来像(和它的很多代码):

 (FContext as IApp1Context).DoSomethingSpecificToApp1
 (FContext as IApp1Context).DoOtherThing;
 ..

事情显而易见,但在我看来并不好读。也许我夸张了;这种情况有一种巧妙的设计技巧,我不知道吗?

3 个答案:

答案 0 :(得分:9)

使用临时变量。在方法开始时分配一次,然后在需要的地方使用它。

var
  AppContext: IApp1Context;
begin
  AppContext := FContext as IApp1Context;

  AppContext.DoSomethingSpecificToApp1;
  AppContext.DoOtherThing;
end;

或者,由于您的IContext对象看起来像是对象的字段,因此请将IApp1Context变量设为同一对象的字段。它甚至可以替换IContext字段,因为IApp1Context已经公开了IContext所做的所有事情。

procedure TCustomer.Initialize(const Context: IContext);
begin
  FContext := Context;
  FAppContext := FContext as IApp1Context;
  // ...
end;

答案 1 :(得分:2)

您如何看待使用泛型的这种可能的解决方案?

亲:没有铸造必要的 down:泛型几乎侵入框架的每个接口和类,使其更复杂..

// framework //
type
  IContext = interface
    function DB;
    ..
  end;

  TContext = class (TInterfaedObject, IContext)
    function DB;
    ..
  end;

  IBusinessObj<T: IContext> = interface
    procedure Initialize(AContext: T);
  end;

  TBusinessObj<T: IContext> = class (TInterfacedObject, IBusinessObj<T>)
  protected
    FContext: T;
  public
    procedure Initialize(Context: T); virtual;
  end;

procedure TBusnessObj<T>.Initialize(Context: T);
begin
  FContext := Context;

  FContext.DB.Connect;
end;

// application //
type
  IApp1Context = interface (IContext)
    procedure DoSomethingElse;
    ..
  end;

  TApp1Context = class(TContext, IContext, IApp1Context)
    function DB;
    procedure DoSomethingElse;
  end;

  TCustomer = class(TBusinessObj<IApp1Context>)
  public
    procedure Initialize(AContext: IApp1Context); override;
  end;

procedure Start;
var
  C: IBusinessObj<IApp1Context>;
begin
  C := TCustomer.Create;
  C.Initializate(TApp1Context.Create);
  ..
end;

procedure TCustomer.Initialize(AContext: IApp1Context);
begin
  inherited;

  FContext.DoSomethingElse // here I can use FContext as a IApp1Context.. 
end;

请评论,谢谢!

答案 2 :(得分:1)

您还可以为您的班级提供一个如下定义的私人函数AppContext

function AppContext : IApp1Context;

begin
Result := FContext as IApp1Context;
end;

这可以避免额外的变量声明并保持强制转换为本地。从客户端代码中你可以写:

AppContext.DoSomethingSpecificToApp1;
AppContext.DoOtherThing