Delphi 中,基于接口,封装类为 BPL 包动态加载的程序架构

DELPHI 的普通程序编译出来比较大,一个空程序也要超过1M。其原因是 DELPHI 的程序把所有需要的库都编译到EXE文件里面去了。这样做有个好处:程序发布简单,只要发布一个 EXE 就搞定。

 

不过,当程序写得很大,又是多人开发,并且程序不断升级,可能还有多个版本的时候,采用包编译方式就有好处了。程序主体 EXE 文件很小,方便升级;程序分成很多BPL包文件,升级某个功能,只需要更换BPL包文件就可以了。

 

更进一步,程序调用BPL包中的功能,如果采用基于接口的方式,则程序根本不用知道BPL包中的类的类型。只要接口不变,BPL包里随便怎么更改都没关系。相当于采用接口的方式实现了多态。

 

多人开发的时候,每个人只要把自己负责的部分,封装为类,然后通过接口输出这个类可以提供的功能。然后把这个类和接口都编译为BPL包,把 BPL 包发布给使用这个类的其他同事就行了。这样避免开发的人面对一大堆不是自己写的代码。对于代码的管理也更简单。



在Delphi中,将一个或多个类,编译为一个 BPL,让需要使用到这几个类的代码来调用,实际上在使用 DELPHI 的时候,我们就随时在应用这个功能 --- DELPHI IDE 里面安装的控件,就是让 IDE 动态加载控件的设计期 BPL。

 

这样的用法有一个问题:你要用到那个类的地方,必须【知道】那个类。也就是必须引用那个类的单元。尽管那个类你已经编译为了 BPL,但你的代码还是需要引用那个类的单元,也就是你需要那个类的 PAS 文件或者 DCU 文件。

 

一个好的程序架构,各类、各单元之间的耦合度,应该尽量低。并且,如果完成该功能的类增加了,比如新写一个相似功能的类编译为另一个BPL文件,那么,你的程序就需要增加对这个新的类的引用,你的程序必须修改源程序,重新编译。

 

因此,我们先针对上述问题,提出我们想要的:

1. 运行期动态加载一个BPL,使用BPL里面的类提供的功能;但不需要知道和引用这个BPL里面的类的单元和类的类型。

2. 增加新的相似功能的类,增加新的 BPL 文件,也只需要在运行期动态加载 BPL 的时候,换掉BPL文件就可以,程序不用重新编译,也不必引用新的类所在地单元。

 

要实现上述两点,可以采用基于接口的方式。首先单独定义一个接口单元。实现该接口的类,需要引用该单元;需要使用这个类提供的功能的程序,也引用该单元。但程序不需要引用类的单元,也不需要知道类的类型。当有新的类实现相似功能的时候,同样实现该接口。对于程序来说,因为都是调用相同的接口,具体是哪个类来实现这个接口程序不用关心,因此程序不需要做任何改动。 采用接口,降低了耦合度,同时提高了灵活性。

 

在上述前提下,首先把接口单元,放入一个单独的包(源代码情况下就是一个单独的 DPK 文件,编译后就是一个单独的 BPL 文件)。编译为BPL文件,同时DELPHI会输出一个 DCP 文件。

 

然后,再将实现该接口的一个类或多个类,放到一个 DPK 里面,因为这些类需要引用接口单元,而接口单元又编译为 BPL 文件,所以这个 DPK 需要引用(require)接口BPL对应的 DCP 文件。这样就可以编译出一个 BPL 文件。

 

而使用该接口的程序,设置为需要运行期包的编译方式,并填入接口单元所在BPL包文件的名字,就会让程序在运行启动时静态加载这个接口单元所在地 BPL 文件,如果文件不存在,则程序运行失败。

 

程序运行起来后,程序的代码可以通过动态加载一个包的方式,将实现接口的类所在的包加载进来。

 

问题来了:程序并不知道类的类型(没有引用类所在单元),如何根据需要创建该类的对象?没有对象实例,何来接口实例?

 

一个简单的办法:自己写一个简单的类工厂。这个类工厂本身,也编译为一个 BPL 包!也同样基于接口!

 

这样的架构,简单的描述就是:

1. 接口定义编译为 BPL 包,让程序静态加载;

2. 实现接口的类,编译为另一个 BPL 包,让程序动态加载;

3. 用类工厂来根据需要创建相应的类的实例,然后可以从该实例获得接口的实例。程序只需要调用接口里的方法、函数、属性等东西就可以了。创建的类不同,实现的功能可能就不同,但因为接口相同,对于使用接口的程序来说,就实现了传说中的【多态】的功能,只是这个多态不是基于类继承的方式,而是基于接口。

 

要让程序编译为运行时静态加载一个 BPL,而不是编译时直接把该 BPL 涉及到的 DCU 编译到程序的 EXE 里面去,需要在 DELPHI IDE 里面做如下设置:

 

Project -- Options -- Packages -- Build with runtime packages 选项打勾,然后在该选项下面的输入框里填上你的程序需要静态加载的 BPL 的名字。注意该输入框里已经默认把 DELPHI 提供的一堆 BPL 的名字都填在里面了。如果那些名字不去掉,则编译后的程序的 EXE 会非常小,但你发布程序的时候就必须带上一大堆 DELPHI 提供的 BPL。好处是,下次再发布程序,只要那台电脑里已经有那些BPL了,你就可以不用拷贝那么多的 BPL 给客户了,只需要给他一个很小的 EXE 文件就好了。

至于动态加载的 BPL,和动态加载 DLL 类似。

 

转:http://hi.baidu.com/pcplayer99/item/b8b11b211e8df43794f62bef


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Delphi的运行时型信息(RTTI)是在程序编译后生成的,它能够提供程序各种对象的型和成员信息。而Borland Package Library(BPL)是一种库文件格式,可以将Delphi代码编译成二进制形式,并且可以在运行时被动态加载。 要使用Delphi的RTTI加载BPL文件,首先需要确保BPL文件已被正确编译生成。在Delphi开发环境,可以通过编译项目生成BPL文件,确保在项目选项的“生成”部分选择“装编译”。 一旦BPL文件生成后,可以在Delphi代码使用RTTI来加载它。在代码,需要首先将BPL文件加载到内存,可以使用LoadPackage函数来实现。LoadPackage函数接受BPL文件的完整路径作为参数,并返回一个HMODULE型的句柄。 使用RTTI加载BPL文件的步骤如下: 1. 使用LoadPackage函数将BPL文件加载到内存,并获取返回的句柄。 2. 使用GetModuleSymbols函数获取BPL文件导出的符号列表。 3. 使用GetAddress函数获取需要使用的符号的地址。 4. 将获取到的地址转换成需要的型,并使用该型的功能。 使用RTTI加载BPL文件可以实现动态加载和调用其他模块的函数、过程和等功能。这使得开发者能够通过加载BPL文件来扩展程序的功能,提高了程序的灵活性和可扩展性。 需要注意的是,在使用RTTI加载BPL文件时,要确保加载BPL文件与应用程序的目标平台、编译器版本等兼容,否则可能会引发不可预料的错误。另外,加载过多的BPL文件也可能导致程序性能下降,因此在设计时应考虑加载BPL文件的数量和大小。同时,加载BPL文件也可能存在安全风险,因此要谨慎选择加载BPL文件来源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值