• delphi接口(抄自万一)


    Delphi 的接口(1) - 前言

    "接口" 的概念和 "类" 特别是 "抽象类" 近似, Delphi 之初并没有接口, 后来(Delphi 3)为了支持 COM 引入了接口, 再后来发展成为 Delphi 重要的语言特性.



    应该先简单了解点 COM, 说到 COM, 能让我想到 "有心栽花花不活, 无意插柳柳成荫" 的古话.
    微软在开发 OLE 时, 有一种需求: 使用其他程序中的对象, 这种需求导致了 COM 的诞生并发扬光大, 而 OLE 却在慢慢地销声匿迹.

    从 COM 到 COM+, 之后好像微软并没有再大力发展(可能是把精力都放到 Net 上去了, 但 Net 也没离开 COM), 它现在仍有着非常广泛的应用, 这应该得益于它先进的思想.

    慢慢道来:
    1、一个二进制的 1 或 0, 这是任何语言都可以识别的;
    2、一个字符, 也是任何语言都可以识别的;
    3、一个整形变量, 也是任何语言都可以识别的;
    4、一个结构体, 也是任何语言都可以识别的;
    5、一个函数也没有问题, 譬如 Delphi 调用 API;
    6、但一个 "对象" 或着 "类" 呢? 这在跨程序、跨语言时就不好识别了.

    COM 解决了这个问题! 并进而应用于网络.



    COM 规定了一个二进制的标准, 这个标准主要针对 "对象方法的声明"(也就是接口), 同时把声明(接口)和实现分开.
    不同的语言都可以来实现这个接口、同时不同的语言(在遵循标准的情况下)也都能识别这个接口, 从而实现的跨语言的对象的交互.

    现在看看这个过程其实是水到渠成、挺自然的; 但好像当初微软的 COM 之路也并不平坦.

    微软通过 COM 组件的方式提供了很多功能, 它们很可能是用 C++ 实现的, 我们用 Delphi 可以很好的使用, 本质上说就是 Delphi 遵循了那个二进制的标准; 相反, Delphi 按这个标准声明、并用自己的语言实现的 COM 组件也能供其他语言使用.

    一个 COM 组件里有什么呢?
    主要是一堆接口(也就是声明)和接口的实现, 每个接口对应一个计数器, 另包含一个叫 "类厂" 的东西.
    使用 COM 步骤可能是这样的:
    1、程序在使用组件之初, 先联系 "接口"; 这应该是从注册表中查询.
    2、找到后, 如果此接口还没有被实现, 马上调用 "类厂" 建立起对象, 并同时给接口计数器加 1.
    3、可能会不止一个程序在使用同一个接口, 但每有使用则 "计数器+1", 每次用完则 "计数器-1".
    4、当接口的使用计数为 0 时, 系统自动释放类厂为该接口建立的对象(垃圾回收机制).

    我们 Delphi 中的接口当然也是这样, 用完会自动释放, 无需手动 free.



    接口在 Delphi 中继续支持着 COM 并继续完善着, 接下来要讨论的是作为语言特性的 "接口" 概念与使用.
    我曾经被 "接口" 置于云雾之中, 一些书也让人越看越糊涂; 明白了以后发现其实挺简单的, 相比 "类" 的规则要简单许多.

    Delphi 的接口(2) - 第一个例子

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        Button3: TButton;
        Button4: TButton;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Button3Click(Sender: TObject);
        procedure Button4Click(Sender: TObject);
      end;
    
      IMyInterface1 = interface
        function Func1: Integer;
        function Func2: Integer;
      end;
    
      IMyInterface2 = interface
        procedure Proc1;
        procedure Proc2;
      end;
    
      TMyClass1 = class(TInterfacedObject, IMyInterface1, IMyInterface2)
      public
        procedure Proc1;
        procedure Proc2;
        function Func1: Integer;
        function Func2: Integer;
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    { TMyClass1 }
    
    function TMyClass1.Func1: Integer;
    begin
      ShowMessage('IMyInterface1.Func1');
      Result := 0;
    end;
    
    function TMyClass1.Func2: Integer;
    begin
      ShowMessage('IMyInterface1.Func2');
      Result := 0;
    end;
    
    procedure TMyClass1.Proc1;
    begin
      ShowMessage('IMyInterface2.Proc1');
    end;
    
    procedure TMyClass1.Proc2;
    begin
      ShowMessage('IMyInterface2.Proc2');
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      c: TMyClass1;
    begin
      c := TMyClass1.Create;
    
      c.Func1;
      c.Func2;
    
      c.Proc1;
      c.Proc2;
    
      c.Free;
    end;
    
    procedure TForm1.Button2Click(Sender: TObject);
    var
      i1: IMyInterface1;
    begin
      i1 := TMyClass1.Create;
      i1.Func1;
      i1.Func2;
    end;
    
    procedure TForm1.Button3Click(Sender: TObject);
    var
      i2: IMyInterface2;
    begin
      i2 := TMyClass1.Create;
      i2.Proc1;
      i2.Proc2;
    end;
    
    procedure TForm1.Button4Click(Sender: TObject);
    var
      c: TMyClass1;
      i1: IMyInterface1;
      i2: IMyInterface2;
    begin
      c := TMyClass1.Create;
    
      i1 := c;
      i1.Func1;
      i1.Func2;
    
      i2 := c;
      i2.Proc1;
      i2.Proc2;
    
    //  c.Free; {}
    end;
    
    end.


    示例注释(现在应该知道的):


    {
      1、接口命名约定 I 起头, 就像类从 T 打头一样.
    
      2、接口都是从 IInterface 继承而来; 若是从根接口继承, 可省略.
    
      3、接口成员只能是方法、属性, 没有字段.
    
      4、接口成员都是公开的, 不需要 private、protected、public、published 等任何访问限制.
    
      5、因为接口只声明、无实现, 也用不到继承与覆盖相关的修饰(virtual、dynamic、abstract、override).
    
      6、一个接口可以从另一个接口继承, 但不能从多个接口继承; 不过 Delphi.Net 已支持接口的多继承了.
    
      7、一个类可以实现多个接口: TMyClass = class(父类, 接口1, 接口2, ...)  end;
    
      8、不过实现接口的类有多么丰富, 接口只拥有自己声明的成员.
    
      9、实现接口的类一般继承于 TInterfacedObject, 直接从 TObject 继承会增加一些麻烦而重复的工作.
    
      10、接口在用完后会自释放, 并同时释放拥有它的类; 这很方便, 但同时带来很多问题.
    }
     

    Delphi 的接口(3) - 关于接口的释放

    代码文件:

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        Button3: TButton;
        Button4: TButton;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Button3Click(Sender: TObject);
        procedure Button4Click(Sender: TObject);
      end;
    
      IMyInterface = interface
        procedure Proc;
      end;
    
      TMyClass = class(TInterfacedObject, IMyInterface)
      public
        constructor Create;
        destructor Destroy; override;
        procedure Proc;
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    constructor TMyClass.Create;
    begin
      inherited;
      ShowMessage('TMyClass.Create');
    end;
    
    destructor TMyClass.Destroy;
    begin
      ShowMessage('TMyClass.Destroy');
      inherited;
    end;
    
    procedure TMyClass.Proc;
    begin
      ShowMessage('IMyInterface.Proc');
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      c: TMyClass;
    begin
      c := TMyClass.Create;
      c.Proc;
      c.Free;
      ShowMessage('**********');
    
    {将依次显示:
       TMyClass.Create
       IMyInterface.Proc
       TMyClass.Destroy
       **********
    }
    end;
    
    procedure TForm1.Button2Click(Sender: TObject);
    var
      i: IMyInterface;
    begin
      i := TMyClass.Create;
      i.Proc;
      ShowMessage('**********');
      //在本段程序的最后, 编译器能判断出接口不再有用, 会释放掉拥有它的类
    
    {将依次显示:
       TMyClass.Create
       IMyInterface.Proc
       **********
       TMyClass.Destroy
    }
    end;
    
    procedure TForm1.Button3Click(Sender: TObject);
    var
      c: TMyClass;
      i: IMyInterface;
    begin
      c := TMyClass.Create;
      i := c;
      //i := IMyInterface(c);   {也可以这样转换}
      //i := c as IMyInterface; {暂时不能使用 as, 接口拥有 GUID 后才可以使用 as 转换}
      i.Proc;
      ShowMessage('**********');
    
    {将依次显示:
       TMyClass.Create
       IMyInterface.Proc
       **********
       TMyClass.Destroy
    }
    end;
    
    procedure TForm1.Button4Click(Sender: TObject);
    var
      i: IMyInterface;
    begin
      i := TMyClass.Create;
      i.Proc;
      i := nil; //可以这样主动释放接口; 同时拥有它的类也会释放
      ShowMessage('**********');
    
    {将依次显示:
       TMyClass.Create
       IMyInterface.Proc
       TMyClass.Destroy
       **********
    }
    end;
    
    end.

     
     
    分类: 接口相关
     

    Delphi 的接口(4) - 接口的属性

    代码文件:

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      end;
    
      {此接口声明了一个 Name 属性; 因为接口没有字段, read/write 都只能从方法}
      IMyInterface = interface
        function GetName : string;
        procedure SetName(val : string);
        property Name : string read GetName write SetName;
      end;
    
      {类实现的是接口的读写方法, 属性还是属于接口的; 类可以提供一个储存属性的字段}
      TMyClass = class(TInterfacedObject, IMyInterface)
      private
        FName: string;
      public
        function GetName: string;
        procedure SetName(val: string);
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    { TMyClass }
    
    function TMyClass.GetName: string;
    begin
      Result := FName;
    end;
    
    procedure TMyClass.SetName(val: string);
    begin
      FName := val;
    end;
    
    { TForm1 }
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      c: TMyClass;
      i: IMyInterface;
    begin
      c := TMyClass.Create;
      i := c;
      i.Name := 'ABC';
      ShowMessage(i.Name); {ABC}
    
      //没有一个 c.Name 存在, 这个属性只属于接口
    end;
    
    end.



    代码文件:

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      end;
    
      {此接口声明了一个 Name 属性; 因为接口没有字段, read/write 都只能从方法}
      IMyInterface = interface
        function GetName : string;
        procedure SetName(val : string);
        property Name : string read GetName write SetName;
      end;
    
      {类实现的是接口的读写方法, 属性还是属于接口的; 类可以提供一个储存属性的字段}
      TMyClass = class(TInterfacedObject, IMyInterface)
      private
        FName: string;
      public
        function GetName: string;
        procedure SetName(val: string);
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    { TMyClass }
    
    function TMyClass.GetName: string;
    begin
      Result := FName;
    end;
    
    procedure TMyClass.SetName(val: string);
    begin
      FName := val;
    end;
    
    { TForm1 }
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      c: TMyClass;
      i: IMyInterface;
    begin
      c := TMyClass.Create;
      i := c;
      i.Name := 'ABC';
      ShowMessage(i.Name); {ABC}
    
      //没有一个 c.Name 存在, 这个属性只属于接口
    end;
    
    end.
    

    代码文件:

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      end;
    
      IMyInterface1 = interface
        function Func(a,b: Integer): Integer;
      end;
    
      TAdd = class(TInterfacedObject, IMyInterface1)
      public
        function Func(a: Integer; b: Integer): Integer;
        destructor Destroy; override;
      end;
    
      TMul = class(TInterfacedObject, IMyInterface1)
      public
        function Func(a: Integer; b: Integer): Integer;
        destructor Destroy; override;
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    { TAdd }
    
    destructor TAdd.Destroy;
    begin
      ShowMessage('TAdd.Destroy');
      inherited;
    end;
    
    function TAdd.Func(a, b: Integer): Integer;
    begin
      Result := a + b;
    end;
    
    { TMul }
    
    destructor TMul.Destroy;
    begin
      ShowMessage('TMul.Destroy');
      inherited;
    end;
    
    function TMul.Func(a, b: Integer): Integer;
    begin
      Result := a * b;
    end;
    
    { TForm1 }
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      I: IMyInterface1;
    begin
      I := TAdd.Create;
      ShowMessage(IntToStr(I.Func(9, 9))); {18}
    
      I := TMul.Create;  {I 在指向新的目标前会先释放前面所属的类}
      ShowMessage(IntToStr(I.Func(9, 9))); {81}
    end;
    
    end.

     
     
    分类: 接口相关
  • 相关阅读:
    很实用的html meta标签实现页面跳转
    oracle 实例名和服务名以及数据库名区别
    Oracle 创建 DBLink 的方法
    Java (六):java中Math常用方法
    Java (四):String,StringBuilder,StringBuffer三者的区别
    ROS Learning-001 安装 ROS indigo
    Windows cmd 将命令(/指令)写到一个文件里,直接运行这个文件。提高工作效率
    Blender 基础 骨架-02 骨架的各种呈现方式
    Blender 基础 骨架 01
    Python 解决 :NameError: name 'reload' is not defined 问题
  • 原文地址:https://www.cnblogs.com/xunmengyoufeng/p/3365124.html
Copyright © 2020-2023  润新知