2016-04-29 27 views
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和我无能为力改变它。

我倒是不喜欢创造许多味精变量,如msgV01:= tissv01.GetmensagemTISS,msgV01:= tissv02.GetmensagemTISS,...等等

+0

为什么你在声明多台相同的接口,我不明白。在普通单元中声明一次,然后在整个程序中使用该单元。 –

+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; 

使用子句中的最后一个单元获得优先级。
这个事实常常被滥用以覆盖内置的类和接口与自定义的。

如果你要延迟根据您可以使用条件编译一些条件的选择。
无论是使用子句中(利用的使用条款顺序的优先效果),

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; 
+0

是的,我知道。这就是我现在正在做的。但是我有许多使用“a”变量的过程和函数。我不得不复制许多行代码才能从“a”变量变为“b”变量。而且我需要根据情况加入两个单位。我想只有一个变量来访问接口,因为它们是相似的,只是改变你的版本和其他没有重要的东西。 –

+0

好的,但我需要在运行时选择单元,不需要编译时间 –

+0

Phuffff,现在我已经涵盖了一切。我厌倦了输入界面和方法名称,所以最后我有点创意。 – Johan