0

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

我使用 xml 数据绑定来生成单位。它们是:

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

4

1 回答 1

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子句中(利用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 ...}.
您也可以{$define ...}在 IDE 中声明。

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;
于 2016-04-29T17:50:01.527 回答