{
  说明:该事例实现的效果,在单个应用或代码量小的项目中,可以完全不用接口委托来完成。
  之所以采用委托接口,主要是应用到:已经实现的接口模块中,在不改变原有代码的情况下,
  需要对其进行扩展;原始模块只需要开放部分功能,但又不能暴露实现细节的场合;
}

unit TestUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

const
  TestMsgGUID: TGUID = '{4BE80D5E-D94B-42BE-9114-077DC2708451}';

type
  //原始接口中新增需要暴露给其它模块的接口定义,公用部分
  ITestMsg = interface
    ['{4BE80D5E-D94B-42BE-9114-077DC2708451}']
    procedure ShowTestMsg;
  end;

//---------------------------------服务模块
  //基类对象,只需要开放ShowTestMsg方法给外部,所以做为按口的实现基类
  TBaseTestMsg = class(TInterfacedObject, ITestMsg)
  public
    //.... 模块已存在的老代码....

//新开放的接口代码方法
    procedure ShowTestMsg; virtual;     //申明成虚拟方法,以便继承类可以重载
  end;

//---------------------------------接口委托对象定义
  TTestMsgClass = class(TInterfacedObject, ITestMsg)
  private
    FTestMsg: ITestMsg;
  public
    property Service: ITestMsg read FTestMsg implements ITestMsg;

constructor Create(AClass: TClass);
    constructor CreateEx(AClass: TClass);      //另一种用法, 不采用TBaseTestMsg做为基类创建委托实例
    destructor Destroy; override;
  end;

//----------------------------------外部引用的业务模块
  //完成具体业务的委托实例
  TETestMsg = class(TInterfacedObject, ITestMsg)
  public
    procedure ShowTestMsg;
  end;

//完成具体业务的委托实例
  TCTestMsg = class(TInterfacedObject, ITestMsg)
  public
    procedure ShowTestMsg;
  end;

TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure DoTest(AClass: TClass; ACreateEx: Boolean = False);     //测试方法
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TBaseTestMsg }

procedure TBaseTestMsg.ShowTestMsg;
begin
end;

{ TTestMsgClass }

constructor TTestMsgClass.Create(AClass: TClass);
var
  vObj: TBaseTestMsg;
begin
  vObj := TBaseTestMsg(AClass.NewInstance);
  FTestMsg := vObj.Create;
end;

constructor TTestMsgClass.CreateEx(AClass: TClass);
begin
  //该方法不采用TBaseTestMsg做为基类创建委托实例,更通用更灵活
  (AClass.NewInstance.Create).GetInterface(TestMsgGUID, FTestMsg);
end;

destructor TTestMsgClass.Destroy;
begin
  FTestMsg := nil;
  inherited;
end;

{ TETestMsg }

procedure TETestMsg.ShowTestMsg;
begin
  ShowMessage('TETestMsg Msg:' + 'OK');
end;

{ TCTestMsg }

procedure TCTestMsg.ShowTestMsg;
begin
  ShowMessage('TCTestMsg 消息:' + '好的');
end;

//--------------------以下为测试代码--------------------------------

procedure TForm1.DoTest(AClass: TClass; ACreateEx: Boolean);
var
  vClass: TTestMsgClass;
  vTest: ITestMsg;
begin
  if ACreateEx then
    vClass := TTestMsgClass.CreateEx(AClass)
  else
    vClass := TTestMsgClass.Create(AClass);

try
    vTest := vClass;
    vTest.ShowTestMsg;
  finally
    vTest := nil;
    FreeAndNil(vClass);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  DoTest(TETestMsg);
  DoTest(TCTestMsg);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  DoTest(TETestMsg, True);
  DoTest(TCTestMsg, True);
end;

end.

Delphi的接口委托示例的更多相关文章

  1. delphi中接口的委托和聚合

    Delphi的TRegistry注册表类 方法详解 Delphi的接口编程入门 delphi中接口的委托和聚合 2009-09-27 10:44:44|  分类: 默认分类 |  标签: |举报 |字 ...

  2. 基于Delphi的接口编程入门

    为什么使用接口? 举个例子好了:有这样一个卖票服务,电影院可以卖票,歌剧院可以卖票,客运站也可以卖票,那么我们是否需要把电影院..歌剧院和客运站都设计成一个类架构以提供卖票服务?要知道,连经理人都可以 ...

  3. Delphi采用接口实现DLL调用

    Delphi使用模块化开发,可以采用DLL或者BPL,两者的区别是BPL只能被同版本的Delphi使用,DLL可以被不同版本和不同开发工具的开发的软件调用. 因此我们的软件大多使用Delphi作为界面 ...

  4. Delphi之通过代码示例学习XML解析、StringReplace的用法(异常控制 good)

    *Delphi之通过代码示例学习XML解析.StringReplace的用法 这个程序可以用于解析任何合法的XML字符串. 首先是看一下程序的运行效果: 以解析这样一个XML的字符串为例: <? ...

  5. Delphi 的接口机制——接口操作的编译器实现过程(1)

    学习COM编程技术也快有半个月了,这期间看了很多资料和别人的程序源码,也尝试了用delphi.C++.C#编写COM程序,个人感觉Delphi是最好上手的.C++的模版生成的代码太过复杂繁琐,大量使用 ...

  6. 国际快递查询接口JAVA示例-trackingmore

    国际快递查询接口 国际快递查询接口的需求量很大,例如一些跨境电商B2C网站.快递查询APP.快递柜.跨境物流公司等都会需要用到国际快递接口. 目前市面上的快递接口,以国内快递居多,有些虽然号称支持多家 ...

  7. Delphi面向对象---接口

    从Delphi3开始支持接口.接口定义了能够与一个对象进行交互操作的一组过程和函数.对一个接口进行定义包含两个方面的内容: 1)一方面是实现这个接口 2)另一方面是定义接口的客户 一个类能够实现多个接 ...

  8. Delphi 的接口机制——接口操作的编译器实现过程(2)

    接口对象的内存空间 假设我们定义了如下两个接口 IIntfA 和 IIntfB,其中 ProcA 和 ProcB 将实现为静态方法,而 VirtA 和 VirtB 将以虚方法实现: IIntfA =  ...

  9. Delphi中的“委托”

    .NET中有委托(Delegate)的概念,其声明形式如下所示:     public delegate void MyDelegate(int aIntParam, string aStringPa ...

随机推荐

  1. echarts饼图不显示数据为0的数据

    首先阐述下为什么会有这个需求,这个和echarts自身的显示效果有关. 如果你选择的展示图形为饼图,然后你的数据里有一条数据为0,那么展示的数据就为一条直线,看上去效果并不好, 会很突兀. 当然如果你 ...

  2. LeetCode(33):搜索旋转排序数组

    Medium! 题目描述: 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值 ...

  3. HRBUST - 1818 石子合并 区间dp入门

    有点理解了进阶指南上说的”阶段,状态和决策“ /* 区间dp的基础题: 以区间长度[2,n]为阶段,枚举该长度的区间,状态dp[l][r]表示合并区间[l,r]的最小费用 状态转移方程dp[l][r] ...

  4. 利用setTimeout延时器 制作广告自动关闭

    模仿广告自动关闭效果 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...

  5. python 全栈开发,Day129(玩具开机提示语,为多个玩具发送点播,聊天界面,app录音,app与服务器端文件传输,简单的对话)

    一.玩具开机提示语 先下载github代码,下面的操作,都是基于这个版本来的! https://github.com/987334176/Intelligent_toy/archive/v1.2.zi ...

  6. python 全栈开发,Day99(作业讲解,DRF版本,DRF分页,DRF序列化进阶)

    昨日内容回顾 1. 为什么要做前后端分离? - 前后端交给不同的人来编写,职责划分明确. - API (IOS,安卓,PC,微信小程序...) - vue.js等框架编写前端时,会比之前写jQuery ...

  7. 2017-2018-2 20155309 南皓芯 Exp3 免杀原理与实践

    报告内容 2.1.基础问题回答 (1)杀软是如何检测出恶意代码的 ? 1:基于特征码 一段特征码就是一段或多段数据.(如果一个可执行文件(或其他运行的库.脚本等)包含这样的数据则被认为是恶意代码) 杀 ...

  8. oracle表分区创建

    一.什么是分区表表分区有以下优点: 1.数据查询:数据被存储到多个文件上,减少了I/O负载,查询速度提高. 2.数据修剪:保存历史数据非常的理想. 3.备份:将大表的数据分成多个文件,方便备份和恢复. ...

  9. 【C++ Primer | 15】虚继承

    虚基类 一.虚基类介绍 多继承时很容易产生命名冲突,即使我们很小心地将所有类中的成员变量和成员函数都命名为不同的名字,命名冲突依然有可能发生,比如非常经典的菱形继承层次.如下图所示: 类A派生出类B和 ...

  10. WCF客户端从服务器下载数据

    1.打开VS选择控制台项目新建一个解决方案Server,然后添加两个类库Contract和Service. 2.在Contract中添加一个接口IFileDownload using System; ...