基于接口,封装类为BPL包动态加载的程序架构一、架构及方案二、DLL群集三、程序结构四、规则(注意事项)1、公共包:EXE及各BPL均buildwith。2、内存共享:ShareMem单元放在引用第一个。3、基类:分为两种,一种为窗口,一种为类。窗口有两个,一个模式窗口,一个非模式窗口。所有窗口必须从基类继承。类也有两个,一个普通类,一个管理类(列表)。所有类必须从基类继承。五、原理在Delphi中,将一个或多个类,编译为一个BPL,让需要使用到这几个类的代码来调用,实际上在使用DELPHI的时候,我们就随时在应用这个功能---DELPHIIDE里面安装的控件,就是让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里面去,需要在DELPHIIDE里面做如下设置:Project--Options--Packages--Buildwithruntimepackages选项打勾,然后在该选项下面的输入框里填上你的程序需要静态加载的BPL的名字。注意该输入框里已经默认把DELPHI提供的一堆BPL的名字都填在里面了。如果那些名字不去掉,则编译后的程序的EXE会非常小,但你发布程序的时候就必须带上一大堆DELPHI提供的BPL。好处是,下次再发布程序,只要那台电脑里已经有那些BPL了,你就可以不用拷贝那么多的BPL给客户了,只需要给他一个很小的EXE文件就好了。至于动态加载的BPL,和动态加载DLL类似。