使几个单元实现具有相同名称的接口

时间:2016-04-29 17:22:44

标签: delphi delphi-units

当您的版本发生变化时,我需要从第三方下载两个或更多单元。

我使用xml databind生成单位。它们是:

unit tissV01;

interface

uses .....;

type
  IXMLMensagemTISS = interface(IXMLNode)
    ['{11773827-F0A1-42E0-99E1-E221DFAF8542}']
    { Property Accessors }
  end;


function GetmensagemTISS(Doc: IXMLDocument): IXMLMensagemTISS;

implementation

function GetmensagemTISS(Doc: IXMLDocument): IXMLMensagemTISS;
begin
  Result := XXXX as IXMLMensagemTISS;
end;

end.

单位tissV02

unit tissV02;

interface

uses .....;

type
  { IXMLMensagemTISS }
  IXMLMensagemTISS = interface(IXMLNode)
    ['{11773827-F0A1-42E0-99E1-E221DFAF8542}']
    { Property Accessors }
    property Cabecalho: string read Get_Cabecalho;
  end;

function GetmensagemTISS(Doc: IXMLDocument): IXMLMensagemTISS;

implementation

function GetmensagemTISS(Doc: IXMLDocument): IXMLMensagemTISS;
begin
  Result := XXXX as IXMLMensagemTISS;
end;

end.

在我的应用程序中,我需要选择我必须使用的单位:

unit test;

interface

uses tissV01,tissV02, .......;

type 
  TMyform = class(TForm)
  public
    msg3:IXMLMensagemTISS;   
  end;

implementation

procedure TMyform.ExecuteMessage:
var 
  xmlTISS : TXmlDocument;
begin
  xmlTISS := TXmlDocument.Create(nil); 
  if condition  then
    msg3 := tissV01.GetmensagemTISS(xmlTISS)
  else msg3 := tissV02.GetmensagemTISS(xmlTISS);
  with msg3.Cabecalho do  something;
end; 

end.

逻辑上,它不起作用,因为IXMLMensagemTISS对两个单元都是通用的。

是否有一些解决方法可以在不必更改接口名称(IXMLMensagemTISS)的名称的情况下执行此操作?

我想简化我的代码,我需要在将来维护这种类型的许多单元。问题是所有实现IXMLMensagemTISS并且我无法改变它。

我不想创建许多msg变量,例如msgV01:= tissv01.GetmensagemTISS,msgV01:= tissv02.GetmensagemTISS,...等等

1 个答案:

答案 0 :(得分:3)

如果您在不同的单位中有两个相同的标识符,则可以在单位名称前加上区分它们。

var
  a: tissV01.IXMLMensagemTISS;
  b: tissV02.IXMLMensagemTISS;

在您的示例代码中,您需要明确选择要使用的接口。

uses
  tissV01, tissV02;  //last unit in uses clause gets priority.

type 
  TMyform = class(TForm)
  public
    msg3: tissV01.IXMLMensagemTISS;   //allowed
    msg2: tissV02.IXMLMensagemTISS;   //allowed
    msgx: IXMLMensagemTISS; //ambigous, will evaluate to tissV02.IXMLMensagemTISS;
  end;

使用条款中的最后一个单元被优先处理 这个事实经常被滥用来覆盖内置类和接口与自定义类。

如果您希望根据某些条件延迟选择,可以使用条件编译 在uses子句中(利用uses子句顺序的优先级效果),

unit DoWork;

interface

uses
 {$ifdef V01HasPriority}
 tissV02, tissV01;
 {$else}
 tissV01, tissV02;
 {$endif}

或明确声明

var
  a: {$ifdef useV01} tissV01.IInt {$else} tissV02.IInt {$endif}

然后使用在{$define V01HasPriority}之前编译的{$ifdef ...}在其他地方做出选择。
您还可以在IDE中声明{$define ...}

Project > Options > Delphi Compiler > Conditional defines

如果接口兼容,则只能在运行时选择接口 这意味着接口继承自共同的祖先 每个接口在IInterface中都有一个共同的祖先,但最好选择尽可能接近两者的接口。

然后将变量声明为共同的祖先:

var
  a: ICommonInterface;
begin
  if x=1 then a:= tissV01.NewXMLInterface
  else a:= tissV02.NewXMLInterface;
  if Supports(a, tissV01.IXMLInt) then tissV01.IXMLInt(a).DoV01Things
  else tissV02.IXMLInt(a).DoV02Things;  

如果两个接口都具有相同的签名,那么事情就会容易得多(而且更加理智)。

var
  a: IXMLCommon;
begin
  if x=1 then a:= tissV01.NewXMLInterface
  else a:= tissV02.NewXMLInterface;
  a.DoCommonThings(param1, param2);

集中决策
当然,如果你有很多决定让它(有时)更好地集中它们,然后将它们传播到整个程序中。

那么为什么不创建一个完成所有决策的单元,如下所示:

unit IvoryTower;

interface

function InterfaceXorY(const person: TPerson): ICommonIntf;

implementation

function InterfaceXorY(const person: TPerson): ICommonIntf;
var
  WhatToDo: TSomething;
begin
  WhatToDo:= DatabaseY.TableX.GetData(Person);
  case WhatToDo of
    XYZolog: Result:= Unit1.I1;
    Galaga: Result:= Unit2.I2;
    Twinbee: Result:= Unit3.I4;
    else Assert(false, 'what to do outside of valid range');
  end; {case}
end;