關(guān)于基于Delphi平臺(tái)的接口編程入門

字號(hào):

為什么使用接口?
    舉個(gè)例子好了:有這樣一個(gè)賣票服務(wù),電*可以賣票,歌劇院可以賣票,客運(yùn)站也可以賣票,那么我們是否需要把電*、、歌劇院和客運(yùn)站都設(shè)計(jì)成一個(gè)類架構(gòu)以提供賣票服務(wù)?要知道,連經(jīng)理人都可以賣票,很顯然不適合把經(jīng)理人也包括到賣票服務(wù)的繼承架構(gòu)中,我們需要的只是一個(gè)共通的賣票服務(wù)。于是,賣票的服務(wù)是個(gè)接口,電*、歌劇院什么的只要都遵循這樣一個(gè)服務(wù)定義就能很好地相互交互和溝通(如果須要的話)。
    如何在Delphi中使用接口
    1、聲明接口
    IMyInterface = interface(IInterface) //說明(1)
    ['{63E072DF-B81E-4734-B3CB-3C23C7FDA8EA}'] //說明(2)
    function GetName(const str: String): String; stdcall;
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; //說明(3)
    function _AddRef: Integer; stdcall; //使接口引用數(shù)加1。
    function _Release: Integer; stdcall;//使接口引用數(shù)減1,當(dāng)小于等于0時(shí)作釋放動(dòng)作。
    end;
    說明(1):如果有繼續(xù)關(guān)系則在括號(hào)里填父接口,否則省卻,如:IMyInterface = interface這樣就行。
    說明(2):此GUID可選,如果要實(shí)現(xiàn)具有COM特性的接口的話則需要加上,Delphi中對(duì)于有GUID的接口在運(yùn)行時(shí)在VMT表的預(yù)定位置生成接口的信息,如接口方法的定義、方法參數(shù)定義能詳細(xì)信息。
    說明(3):接口必須實(shí)現(xiàn)這三個(gè)函數(shù)。
    2、接口的實(shí)現(xiàn)
    接口服務(wù)是由類來實(shí)現(xiàn)的。
    TIntfClass = class(TObject, IMyInterface)
    private
    FCounter: Integer;
    FRefCount: Integer;
    public
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    ...
    end;
    3、獲取接口
    a. 使用類型轉(zhuǎn)換。 如:
    var aIntf: IMyInterface;
    begin
    aObj := TIntfClass.Create;
    try
    aIntf := (IMyInterface(aObj);
    ...
    b. 利用Delphi編譯器內(nèi)建機(jī)制。 如:aIntf := aObj。
    c. 利用對(duì)象的QueryInterface方法。如OleCheck(aObj.QueryInterface(IID, aIntf)); 只能存取有GUID的COM接口。
    d. 利用as操作符。
    使用as操作符必須符合下面條件:
    1.接口必須明確地指定是從IInterface接口繼承下來。
    2.必須擁有GUID值
    在Delphi7中接口的實(shí)現(xiàn)類還必須是從TInterfacedObject繼承下來才行,如:
    TIntfClass = class(TInterfacedObject, IMyInterface)
    4、接口和對(duì)象生命期
     因?yàn)镈elphi會(huì)自行檢查接口如果在使用后沒有釋放而在生成的程序里加上釋放代碼,但也因這樣帶來了問題,如下面代碼:
    var
    i: Integer;
    aObj: TIntfClass;
    aIntf: IMyInterface;
    begin
    aObj := TIntfclass.Create;
    try
    aIntf := aObj;
    aIntf.GetName...
    finally
    aIntf := nil;
    FreeAndNil(aObj);
    end;
    上面的代碼執(zhí)行的話會(huì)產(chǎn)生存取違規(guī)錯(cuò)誤,是因?yàn)閷?duì)接口置nil時(shí)已釋放接口,而FreeAndNil(aObj)會(huì)再釋放aIntf一次,而在對(duì)aIntf置
    nil時(shí)已釋放了該對(duì)象。解決這個(gè)問題只要不讓接口干擾對(duì)象的生命期就可以了,在Release中只需減引用計(jì)數(shù)而不做釋放的動(dòng)作。
    function TIntfClass._Release: Integer;
    begin
    Result := InterlockedDecrement(FRefCount);
    end;