全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1591
推到 Plurk!
推到 Facebook!

Interface 在DELPHI里的用法示例

 
pcplayer99
尊榮會員


發表:146
回覆:790
積分:632
註冊:2003-01-21

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-06-07 18:00:26 IP:219.134.xxx.xxx 未訂閱
Interface 在DELPHI里的用法示例    任务描述: 我们有4个类,分别生成4个对象:A、B、C、D    A需要调用B的方法,把数据送给B; 然后,B调用C的方法,把A送来的数据送给C; 然后,C调用D的方法,把B送来的数据送给D;    然后,当D使用完这个数据后,D要调用C的方法将处理结果通知C; C再把处理结果通知B; B再把处理结果通知A;    要求: 写A、B、C、D四个类的时候,要避免对象之间的紧密偶合。按传统做法,大概是让A、B、C、D四个类从同一个实现了发送数据和通知这两个方法的父类继承下来。如果因为某种原因,假设B类必须从其它父类继承,就没办法了。 要做到:1. 每个类都不用考虑从哪个父类继承;2. 每个类都不知道别的类。在写B类的时候,不知道有A类或有C类的存在,不引用定义A类或B类的单元。    在Delphi里,我们可以使用Interface来达到这个目的。    首先,单独采用一个单元来定义Interface:    
unit Unit2;    interface    uses Classes;    type
  IMySend2=interface
    procedure SendData(AData:string; AEventList:TInterfaceList);
  end;      IMyEvent2=interface
    procedure SendDataSuccess(AData:string;  AEventList:TInterfaceList);
  end;    implementation    end.
所有的A、B、C、D几个类,都只需要知道Unit2这个单元就行了。它们之间互相不用知道。 每个实现上述接口方法的类,都把自己的通知接口加到AEventList:TInterfaceList里去。最后,每个类在被通知到的时候,都可以根据传来的这个通知接口List,取得发数据给自己的类的通知接口,来通知到应该被通知的类。 下面的代码是实现接口的类。需要注意的是,每个类完全可以写在不同的单元里,单元之间不用互相引用,每个类不用知道其它类。
unit Unit5;
{---------------------------------------------------------
  实验:A类调用B类实现的接口方法,把数据和A类自己实现的通知接口方法发送给B;
  B类再将数据和B类自己的通知接口方法发送给C;C类再发送给D
  最后,D类再通知回C,C通知回B,B通知回A
  数据流经过的每个类,都把自己的通知接口方法指针加入到一个LIST中去,传给下一级
--------------------------------------------------------------------------}
interface    uses Unit2,Dialogs, SysUtils,Classes;    type
  TClassD=class(TInterfacedObject,IMySend2) //最后一个接收数据的类
  public
    procedure SendData(AData:string; AEvenTInterfaceList:TInterfaceList);
  end;      TClassC=class(TInterfacedObject,IMySend2,IMyEvent2)
  public
    FMySend2:IMySend2;
    procedure SendData(AData:string; AEvenTInterfaceList:TInterfaceList);
    procedure SendDataSuccess(AData:string; AEvenTInterfaceList:TInterfaceList);//IMYEvent2
  end;      TClassB=class(TInterfacedObject,IMySend2,IMyEvent2)
  public
    FMySend2:IMySend2;
    procedure SendData(AData:string; AEvenTInterfaceList:TInterfaceList);
    procedure SendDataSuccess(AData:string; AEvenTInterfaceList:TInterfaceList);//IMYEvent2
  end;      TClassA=class(TInterfacedObject,IMyEvent2) //第一个发数据的类
  public
    FMySend:IMySend2; //这是C实现的接口        procedure SendDataSuccess(AData:string; AEvenTInterfaceList:TInterfaceList);//IMYEvent2
    procedure DoSend(AData:string); //由程序调用,主动发出数据给C
  end;    implementation    { TClassA }        { TClassD }    procedure TClassD.SendData(AData: string; AEvenTInterfaceList: TInterfaceList);
var
  AEvent:IMyEvent2;
begin
  if AEvenTInterfaceList.Count>0 then
  begin
    AEvent:=IMyEvent2(AEvenTInterfaceList[AEvenTInterfaceList.Count-1]);   //取出最近的一条接口
    AEvenTInterfaceList.Delete(AEvenTInterfaceList.Count-1);  //将此接口从LIST里删除
    AEvent.SendDataSuccess(AData,AEvenTInterfaceList); //调用此接口通知前一个对象,并将List传给那个对象
    AEvent:=nil;
  end;
end;    { TClassC }    procedure TClassC.SendData(AData: string; AEvenTInterfaceList: TInterfaceList);
var
  MyEvenTInterfaceList:TInterfaceList;
begin
  //此方法被B调用来输入数据,并在这里调用D类的接口将数据送给D
  //FMySend2 由程序来将D的接口放进来。
  if Assigned(AEvenTInterfaceList) then
  begin
    MyEvenTInterfaceList:=AEvenTInterfaceList;
  end
  else
  begin
    MyEvenTInterfaceList:=TInterfaceList.Create;
  end;
  MyEvenTInterfaceList.Add(IMyEvent2(self));   //把自己的通知接口加到列表里去,送给下一级。      FMySend2.SendData(AData 'C',MyEvenTInterfaceList);
end;    procedure TClassC.SendDataSuccess(AData: string;
  AEvenTInterfaceList: TInterfaceList);
var
  AEvent:IMyEvent2;
begin
  ShowMessage('C类被通知= ' AData);
  if AEvenTInterfaceList.Count>0 then
  begin
    AEvent:=IMyEvent2(AEvenTInterfaceList.Items[AEvenTInterfaceList.Count-1]);
    AEvenTInterfaceList.Delete(AEvenTInterfaceList.Count-1);
    AEvent.SendDataSuccess(AData,AEvenTInterfaceList);
    AEvent:=nil;
  end;
end;    { TClassB }    procedure TClassB.SendData(AData: string; AEvenTInterfaceList: TInterfaceList);
var
  MyEvenTInterfaceList:TInterfaceList;
begin
  //此方法被B调用来输入数据,并在这里调用D类的接口将数据送给D
  //FMySend2 由程序来将D的接口放进来。
  if Assigned(AEvenTInterfaceList) then
  begin
    MyEvenTInterfaceList:=AEvenTInterfaceList;
  end
  else
  begin
    MyEvenTInterfaceList:=TInterfaceList.Create;
  end;
  MyEvenTInterfaceList.Add(IMyEvent2(self));   //把自己的通知接口加到列表里去,送给下一级。      FMySend2.SendData(AData 'B',MyEvenTInterfaceList);
end;    procedure TClassB.SendDataSuccess(AData: string;
  AEvenTInterfaceList: TInterfaceList);
var
  AEvent:IMyEvent2;
begin
  ShowMessage('B类被通知= ' AData);
  if AEvenTInterfaceList.Count>0 then
  begin
    AEvent:=IMyEvent2(AEvenTInterfaceList.Items[AEvenTInterfaceList.Count-1]);
    AEvenTInterfaceList.Delete(AEvenTInterfaceList.Count-1);
    AEvent.SendDataSuccess(AData,AEvenTInterfaceList);
    AEvent:=nil;
  end;
end;    { TClassA }    procedure TClassA.DoSend(AData:string);
var
  MyEvenTInterfaceList:TInterfaceList;
begin
  MyEvenTInterfaceList:=TInterfaceList.Create;
  MyEvenTInterfaceList.Add(IMyEvent2(self)); //一定要加强制类型转换!
  FMySend.SendData(AData,MyEvenTInterfaceList);
end;    procedure TClassA.SendDataSuccess(AData: string;
  AEvenTInterfaceList: TInterfaceList);
var
  AEvent:IMyEvent2;
  i:Integer;
begin
  ShowMessage('A类被通知' AData);
  if AEvenTInterfaceList.Count>0 then
  begin
    ShowMessage('接口列表里还有接口指针,奇怪!');
    for i:=AEvenTInterfaceList.Count-1 downto 0 do
    begin
      AEvent:=IMyEvent2(AEvenTInterfaceList.Items[i]);
      AEvent:=nil;
      AEvenTInterfaceList.Delete(i);
    end;
  end
  else
  begin
    ShowMessage('接口列表里没有接口指针了。');
  end;
  AEvenTInterfaceList.Free;
end;    end.
最后,写一个程序来测试结果,会看到,的确符合程序里给的调用顺序:
procedure TForm1.Button5Click(Sender: TObject);
var
  AClassA:TClassA;
  AClassB:TClassB;
  AClassC:TClassC;
  AClassD:TClassD;
begin
  AClassA:=TClassA.Create;
  AClassB:=TClassB.Create;
  AClassC:=TClassC.Create;
  AClassD:=TClassD.Create;      AClassA.FMySend:=IMySend2(AClassB);
  AClassB.FMySend2:=IMySend2(AClassC);
  AClassC.FMySend2:=IMySend2(AClassD);      AClassA.DoSend('你好吗?');
end;
顺便提一下,使用接口还有一个好处,是当增加一个F类,而且把F类插到数据传递的中间,比如A->B->F->C->D,然后D处理完后通知顺序是D->C->F->B->A,完全不用更改其它类。仅仅需要增加一个实现了上述两个接口的F类,然后在程序里把F类插进去就可以了。这样做应该是对程序的改动最小的一种方法了。 这里值得注意的一个语法问题: 上面有这样的语句:AClassA.FMySend:=IMySend2(AClassB); 在语法上来看,可以写成这样:AClassA.FMySend:=AClassB;完全没问题。一样可以在ClassA里调用到ClassB里的接口方法。 但是,如果把接口加到TInterfaceList里去,就好象上面的这句:MyEvenTInterfaceList.Add(IMyEvent2(self)),如果写成: MyEvenTInterfaceList.Add(self),编译完全没问题,能跑起来。但是,当从TInterfaceList里把接口取出来的时候,也就是执行这一句:AEvent:=IMyEvent2(AEvenTInterfaceList[AEvenTInterfaceList.Count-1])的时候,就会出AV错误。 结论:当把接口加入到TInterfaceList里的时候,一定要做强制类型转换,转换为你要的接口!然后取出来的时候才会正确。但当把接口作为一个类的私有变量的时候,可以直接把实现该接口的类指给它也可以。
系統時間:2024-05-19 2:36:44
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!