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


你可能感兴趣的:(Delphi,BPL包,与,DLL)