Interface 在DELPHI里的用法示例 |
|
pcplayer99
尊榮會員 發表:146 回覆:790 積分:632 註冊:2003-01-21 發送簡訊給我 |
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里的时候,一定要做强制类型转换,转换为你要的接口!然后取出来的时候才会正确。但当把接口作为一个类的私有变量的时候,可以直接把实现该接口的类指给它也可以。 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |