bpl插件系统开发(2)

插件规范-----------插件必须实现一个接口,该接口通过 GetObject,SetObject方法让容器和插件能够交互数据.

IPlugin = interface
        ['{48BF4000-B028-4B57-9955-B1A8305DA394}']
        function GetRunResult: TObject; //用于向容器返回执行Execute后的结果
        //用于容器传如执行参数,通常会显示一个Form让用户输入,如果用户存入了
        procedure SetRunParam;
        function GetInfo: TPluginInfo;  //向容器返回插件的信息
        {
        用于容器调用配置插件的持久性配置,
        通常会显示插件内的一个配置Form,
        并可以将Form中的用户输入存入插件配置目录
        }
        procedure EditConfig;
        procedure Execute;              //执行插件

上面是插件接口的定义(与上一节的,略有不同),这样的定义具有通用性,我们定义的原则就是不能有任何特定于某个插件的东西.

   原来我是想使用这样的架构思想来构建一个完全由插件构成的软件,如同eclipse,但是发现这样的想法有点空中楼阁的感觉,为什么这样说呢?我来举个例子:

   我们设想这样的一个系统,它打开数据库,并打开一个表,修改记录并提交更新.这是一个数据库系统最基本的应用.

   容器的工作大概情况是这样:

   1.    从Database.bpl得到一个adoConnection,
   2.

         传入adoConnection参数给OpenQuery.bpl,并得到返回数据TClientDataset;
   3.

         传入这个TClientDataset参数给ProcessData.bpl,它将数据载入界面并显示给用户,执行完毕后,容器会得到一个Delta封包,包含了用户所做的更新.
   4.

         将该Delta封包参数和adoConnection参数传递给UpdateData.bpl, 由它做数据库的更新.
   5.

         传入adoConnection参数给OpenQuery.bpl,并得到返回数据TClientDataset;
   6.

         传入这个TClientDataset参数给ProcessData.bpl,它将数据载入界面并显示给用户,执行完毕后,容器会得到一个Delta封包,包含了用户所做的更新.
   7.

         将该Delta封包参数和adoConnection参数传递给UpdateData.bpl, 由它做数据库的更新.
   8.

         传入adoConnection参数给OpenQuery.bpl,并得到返回数据TClientDataset;
   9.

         传入这个TClientDataset参数给ProcessData.bpl,它将数据载入界面并显示给用户,执行完毕后,容器会得到一个Delta封包,包含了用户所做的更新.
  10.

         将该Delta封包参数和adoConnection参数传递给UpdateData.bpl, 由它做数据库的更新.
  11.

         传入adoConnection参数给OpenQuery.bpl,并得到返回数据TClientDataset;
  12.

         传入这个TClientDataset参数给ProcessData.bpl,它将数据载入界面并显示给用户,执行完毕后,容器会得到一个Delta封包,包含了用户所做的更新.
  13.

         将该Delta封包参数和adoConnection参数传递给UpdateData.bpl, 由它做数据库的更新.

容器负责了整个工作的调度,它完全采用插件来完成每一步工作,我们可以实现不同的bpl来替换其中的相应角色,例如:

    *    使用Database4SqlServer.bpl来提供对另一个数据库的访问(当然这可以使用不同的connectionString达到同样的效果,而且更简单,这里只是为了说明)
    *    使用ProcessDataByRzLib.bpl来给用户呈现不同的界面控件
    *    使用UpdateDataAndLog.bpl来更新数据,使在更新数据的同时写入日志

而我们的容器不需要做任何的更改,它只明白,需要4个不同的类可以完成工作,而各个角色如何来完成角色工作,他并不关心,它能驱动这些类,让系统运转起来.

      这样的系统看起来已经很不错了,但是容器本身必须知道自己要干什么,必须知道如何组织载入的插件,以及它们的调用顺序,数据如何通过容器做为中转在插件之间交互.我们可不可以让容器也被什么东西来驱动起来呢?或者说容器的行为能够被配置起来,由外部来告知容器,这样容器本身就具有了可移植性.

   有关面向接口编程

   面向接口编程意味着系统中由一个管理程序,它组织许多的接口协调完成任务,它区别于旧式的系统在于被管理者是接口,而不是对象,这样的模式给了我们开发系统时松耦合的可能.但基于delphi的程序,我们可以对某个接口实现n个类,并在编译过程中确定由哪一个类来具体进行工作,这样的系统可以说扩展性很好了,举个例子来说,如果需要从外部文件读入信息,

   传统方式:

function ReadConfig:string;
begin
    with TIniFile.Create(someFile) do
    begin
        try
            result :=ReadString(aSection,aConfigName);
        finally
            Free;
        end;
    end;
end;


当需要更改为从xml读取文件后,需要修改这个函数,或者重载这个函数,不可避免的所在单元的代码将不断扩大,
而使用面向接口方式将会这样来撰写

定义接口

IConfig = interface
        function GetConfig:string;
    end;

ini实现

TIniConfig = class(TInterfacedObject ,IConfig)
        function GetConfig:string;
    end;
end;

调用者的代码将不再是:

ReadConfig;

而是

(TIniConfig.Create as IConifg).GetConfig;


当实现了

TXmlConfig = class(TInterfacedObject ,IConfig)
        function GetConfig:string;
    end;
end;

那么调用者可以

(TXmlConfig.Create as IConifg).GetConfig;

这表示调用者可以使用不同的类来为自己提供服务,例如可以声明一个 ITransaction,定义事务的3个方法,

那么,你可以有两个实现-----基于bde的实现和基于 ado的实现,当你切换数据连接时将非常的方便.

插件

然后这样的系统在架构上已经达到了我们的要求,唯一不太完美的是一旦有了切换,我们需要重新编译整个程序,分发....怎么解决它,我们需要一个可以动态载入到程序中的实现,并能配置容器告知容器我们切换了实现..

对的,在java下我们可以发布jar包,而jar包的类通过xxx.xxx.xxx方式保证了类的唯一性,java中各种框架的配置文件90%都有class="xxx.xxx.xxx"之类的声明,而Spring框架更是将这种插件的方式用到了一个可以说是理想的境界,这种机制叫做"依赖注入",而我们在delphi中该如何实现类似的应用(水平不够,不敢说相同的应用)

构思一下:

   1.    容器(即应用程序)完全按照面向接口编程
   2.    容器读入一个外部配置文件来确定每个接口的具体实现类的名称
   3.    载入bpl(bpl中注册了实现某接口的类,以让宿主程序可以访问到)
   4.    通过rtti(类似java的反射)创建类的实例
   5.    将该实例as 成接口,容器使用该实例完成工作.
   6.    当提供某个接口的不同实现时,发布bpl,更新容器配置文件,完成切换

这就是我想开发的插件系统,一个最花精力的事情就是容器到底需要哪些接口来完成一个应用.那么我们需要对现有的应用进行合理的分割,将可能出现变化的部分抽象成接口,将原有的代码实现在一个实现该接口的类中,设想一下一个完整的C/S结构的mis系统需要哪些接口来完成整个应用.

# 压缩文件 F:\rar\delphi控件包\FreeZ_MadCollection.v2.5.7.0_FS.rar 2000-07-09 15:17 0 8 madBasic\Demos\under construction 2000-07-09 15:17 0 8 madDisAsm\Demos\under construction 2000-07-09 15:17 0 8 madKernel\Demos\under construction 2000-07-09 15:17 0 8 madSecurity\Demos\under construction 2003-11-22 16:34 3318 1210 madCodeHook\PowerBasic\ProcessAPI.bas 2003-11-22 16:34 3795 447 madCodeHook\PowerBasic\ProcessFunc.bas 2003-11-23 12:50 1840 208 madCodeHook\PowerBasic\test-DllInjector.bas 2003-11-23 12:51 5308 882 madCodeHook\PowerBasic\test.bas 2004-10-03 10:50 8256 1428 madShell\Demos\DesktopPosSaver.bdsproj 2004-10-03 11:01 8252 77 madCodeHook\Demos\system wide\VariousDlls\DllInjector.bdsproj 2005-04-29 18:01 8243 72 madExcept\Demos\EC.bdsproj 2004-10-03 11:00 8246 80 madCodeHook\Demos\system wide\VariousDlls\Empty.bdsproj 2004-10-03 10:36 8249 77 madExcept\Demos\ExcCatch.bdsproj 2004-10-03 11:00 8253 78 madCodeHook\Demos\system wide\VariousDlls\HookDirect3D.bdsproj 2004-10-03 11:01 8256 77 madCodeHook\Demos\system wide\VariousDlls\HookLoadLibrary.bdsproj 2004-10-03 10:56 8254 78 madCodeHook\Demos\system wide\PrintMonitor\HookPrintAPIs.bdsproj 2004-10-03 11:01 8260 78 madCodeHook\Demos\system wide\VariousDlls\HookProcessCreation.bdsproj 2004-10-03 10:55 8263 81 madCodeHook\Demos\system wide\HookProcessTermination\HookProcessTermination.bdsproj 2004-10-03 10:55 8258 74 madCodeHook\Demos\system wide\HookProcessTermination\HookTerminateAPIs.bdsproj 2004-10-03 10:55 8254 227 madCodeHook\Demos\system wide\HookProcessTermination\InjectService.bdsproj 2004-1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值