转:认识MyBean
1、 初步体验
我们先看一个框架自带的例子,以增加感性认识。打开samples\singleDEMO示例项目。这个示例演示了在一个EXE程序内,使用插件的概念调用两个窗口。其中包括一个主窗体 ufrmMain.pas文件,2 个作为插件的子窗体文件(Child目录),三个接口文件(Interface目录)。
项目结构如下图:
我们先看主窗体
主窗体的主要代码:
procedure TfrmMain.btnSingletonFormClick(Sender: TObject); //创建一个单实例窗体
begin
with TMyBeanFactoryTools.getBean('singletonDEMO') as IShowAsNormal do
begin
showAsNormal;
end;
end;
procedure TfrmMain.Button1Click(Sender: TObject); //创建一个Bean窗体
begin
with TMyBeanFactoryTools.getBean('tester') as IUIForm do
try
showAsModal;
finally
UIFormFree;
end;
end;
注意上面红色代码部分,都有一个getBean方法,带一个字符串参数表示插件名称,调用后返回插件对象,然后通过as 操作,转换为对象支持的接口类型(对接口不熟悉的朋友请参阅相关知识)。上面这个getBean方法是TMyBeanFactoryTools 类的一个类方法。
TMyBeanFactoryTools 类本身定义在mybean.tools.beanFactory单元中,所以主窗体需要在引用列表中加入这个单元。
主窗体调用接口非常简单,通过调用TMyBeanFactoryTools的getBean方法,传入插件名称即可返回插件对象,并访问插件的方法。
这种以“插件”的方式调用子窗体,可以看到主窗口并没有引用(uses)子窗口单元文件。也就是说主窗体与子窗体实现了“解藕”。
那么,getBean方法为什么能通过名字找到插件呢?按照猜测,子窗体应该通过什么方法向框架系统进行了某种形式的“注册登记”,这样主窗体才能查找到。
所以,我们接着看子窗体的实现。我们打开其中的ufrmSingleton单元,它的窗体界面如下:
再查看它的代码:
type
TfrmSingleton = class(TForm, IFreeObject, IShowAsNormal)
Memo1: TMemo;
private
{ Private declarations }
public
{ Public declarations }
procedure FreeObject; stdcall;
procedure showAsNormal; stdcall;
end;
看到现在,我们还没有发现子窗体究竟做了什么“注册登记”的操作。不要急,在代码最后,我们发现了initialization段的代码,这段代码在单元刚载入时初始化。那么这里它做了什么呢?
initialization
beanFactory.RegisterBean('singletonDEMO', TfrmSingleton);
beanFactory.configBeanSingleton('singletonDEMO', true);
我们发现有一个 beanFactory 对象(实际是一个方法function beanFactory: TBeanFactory;),顾名思义,应该是一个bean工厂,专门生产bean(这里也就是我们要做的插件)。这个工厂类有一个RegisterBean方法,把插件注册到某个“登记簿”中去。而'singletonDEMO'就是插件登记的名字,TfrmSingleton是插件的类型。这就验证了我们的猜测。
后面的beanFactory.configBeanSingleton('singletonDEMO', true),则是指明这个插件是个单例模式的插件,即只能建立一个对象实例。
那么,这个beanFactory类型又是哪里声明的呢?查看一下,在 mybean.core.beanFactory;单元中。所以这个子窗体的uses列表中也有这个单元的名称。
我们暂且不去探究beanFactory的内部是如何工作的,先只要知道它在单元初始化部分登记了插件的类名称,把它登记到了框架核心内部的一份“登记簿”中去。然后主程序窗体通过TMyBeanFactoryTools.getBean (插件名称) 方法调用,通过查找内部“登记簿”,获得插件的类别,并建立类的实例,转换成约定的接口。这就是框架工作的大致流程了。
主程序端 Uses mybean.tools.beanFactory; TMyBeanFactoryTools.getBean获取插件实例 |
插件端 Uses mybean.core.beanFactory beanFactory.RegisterBean() 注册插件类 |
登记的插件列表 |
当然,作为插件的子窗体,也应该有“与从不同”的自觉。因为它肯定要比普通的窗体对象承担一些额外的功能。当然,作为框架使用者来说,这种“不同”之处当然是越少越好,这样使用myBean框架才会不那么繁琐。
那么,作为myBean插件对象的窗体,与普通窗体的不同处到底在哪里呢?要怎么做才能成为一个插件呢?
看TfrmSingleton 的定义:
TfrmSingleton = class(TForm, IFreeObject, IShowAsNormal)
这个窗体,在普通TFORM基础上,实现了两个接口IFreeObject和IShowAsNormal,这两个接口分别定义了FreeObject方法和showAsNormal方法。那么IFreeObject和IShowAsNormal本身定义在哪里呢?
通过查找,我们发现 IFreeObject定义在mybean.core.intf单元中,这是框架提供的核心单元,暂不去管它。
而IShowAsNormal定义在uIFormShow单元中:
IShowAsNormal = interface(IInterface)
['{4A2274AB-3069-4A57-879F-BA3B3D15097D}']
procedure showAsNormal; stdcall;
end;
(因为引用了这两个接口,所以不要忘了uses mybean.core.intf和uIFormShow单元)
而FreeObject方法和showAsNormal方法的实现都很普通。freeObject就是调用self.Free 把对象自身free掉。而showAsNormal就是一个最普通不过的show()。
再回到主窗口的代码,看它是如何调用这个子窗体的:
with TMyBeanFactoryTools.getBean('singletonDEMO') as IShowAsNormal do
begin
showAsNormal;
end;
我们发现,'singletonDEMO'正是子窗口向框架注册时用的名字,而IShowAsNormal 正是子窗口实现的接口之一。主窗口中也引用了这个接口文件,所以可以通过这个接口调用方法,而不管子窗体究竟是什么类型的对象。
而实际上,myBean并不强制要求子窗口一定要实现某个特定的接口,你完全可以随便设定子窗口要实现的接口。唯一的约定,就是主窗口和子窗口(作为插件)之间都要遵循同一套接口,以便主窗口在通过GetBean获得子窗口对象后,能够转型为约定的接口并调用接口定义的方法。myBean是通过接口实现主窗体与插件之间沟通的。
当然,为了开发的便利,框架约定了一个IFreeObject接口。如果插件实现了这个接口,则它就可以自己管理生存期,而不需要程序员手动去销毁。
在这个示例中,有两个子窗体,其中一个TfrmSingleton实现了IFreeObject接口,另一个TfrmTester则没有实现这个接口,在使用后需要程序员手动释放,见主窗体的代码:
with TMyBeanFactoryTools.getBean('tester') as IUIForm do
try
showAsModal;
finally
UIFormFree; //手动释(销毁)插件对象
end;
这个UIFormFree方法也是IUIForm 接口中定义的,在TfrmTester中实现了这个接口方法:
procedure TfrmTester.UIFormFree;
begin
self.Free;
end;
上面啰啰嗦嗦分析了这么多,其实总结起来就是以下内容:
主窗体端
① 引用mybean.tools.beanFactory (定义TMyBeanFactoryTools)
② 调用TMyBeanFactoryTools.getBean方法获取插件对象
插件端:
① 引用:mybean.core.beanFactory (beanFactory类的RegisterBean,configBeanSingleton方法),mybean.core.intf (定义FreeObject接口)
② 2、调用:beanFactory.RegisterBean方法注册插件,beanFactory.configBeanSingleton方法配置配件信息。
2、进一步探索
看完了几个窗体的代码,现在我们再来查看这个项目的源代码,看使用myBean框架还需要做些什么准备工作。
program singleDEMO;
uses
Forms,
mybean.core.beanFactory,
mybean.console,
ufrmMain in 'ufrmMain.pas' {frmMain},
ufrmTester in 'Child\ufrmTester.pas' {frmTester},
uIUIForm in 'Interface\uIUIForm.pas',
ufrmSingleton in 'Child\ufrmSingleton.pas' {frmSingleton},
uIShow in 'Interface\uIShow.pas',
uIFormShow in 'Interface\uIFormShow.pas';
{R *.res}
begin
Application.Initialize;
registerFactoryObject(beanFactory, 'default');
Application.MainFormOnTaskbar := True;
Application.CreateForm(TfrmMain, frmMain);
Application.Run;
end.
注意上面红色部分代码,首先它引用了 mybean.core.beanFactory和 mybean.console两个核心单元。然后在代码执行部分注册了一个工厂类的实例:registerFactoryObject(beanFactory, 'default')。
通过上述单元引用,框架运行所需要的环境就建立了。
v 本章小结:
要使用myBean框架,需要做以下几个步骤:
l 主程序端
1、在主程序项目文件(.dpr文件)中引用 mybean.console (提供插件框架环境);
2、在主程序项目文件(.dpr文件)的begin end 部分,添加applicationContextInitialize命令,初始化框架执行环境,载入必要的插件工厂(如果没有找到配置文件,将自动载入程序所在目录下的DLL插件和plugin子目录下的bpl插件);
3、在需要引用插件的单元文件开头,引用mybean.tools.beanFactory单元,并用TMyBeanFactoryTools.getBean('TestDll') as Ixxxxxx (Ixxxxxx 为插件与主程序共同约定的接口)的形式调用插件。
l 插件端(以DLL为例):
1、建立DLL项目,在项目文件中引用 uses mybean.core.beanFactory单元,以提供注册插件所需的工厂类;
2、在项目文件的begin .... end 段内,以beanFactory.RegisterBean('beanIDxxx',TBeanClassxxx)的方式注册插件。其中TBeanClassxxx可以是DLL中定义的任意类标识符(包括窗体),'beanIDxxx'是自己登记这个类时用的唯一标识符号;
3、上述第1-2步注册插件的过程也可以分散在DLL的各单元的 initialization 段。相关单元需要引用 mybean.core.beanFactory单元;
4、注册的插件要实现与主程序共同约定的接口,以供主程序调用。
3、延伸阅读(可选,不影响对框架的使用)
我们先分析mybean.console单元的作用。既然它在uses后就起了作用,说明它在initialization 段里执行了一些东东,所以我们先去看这里。
Initialization
{建立一个记录运行日志的TSafeLogger类型对象,并保存到__beanLogger全局变量中}
__beanLogger := TSafeLogger.Create;
__beanLogger.setAppender(TLogFileAppender.Create(False));
__beanLogger.start;
{建立一个TKeyMapImpl类型的对象,保存到 __instanceKeyMap}
__instanceKeyMap := TKeyMapImpl.Create;
__instanceKeyMapKeyIntf := __instanceKeyMap;
{主程序实例的上下文环境对象}
__instanceAppContext := TApplicationContext.Create;
{转化成接口}
__instanceAppContextAppContextIntf := __instanceAppContext;
mybean.core.intf.appPluginContext := __instanceAppContext;
mybean.core.intf.applicationKeyMap := __instanceKeyMap;
appPluginContext.checkInitialize;
上面代码的最后一行,是执行checkInitialize ,我们继续跟踪它到底干了啥:
procedure TApplicationContext.checkInitialize;
var
lvConfigFiles:String;
begin
if FFactoryObjectList.Count = 0 then
begin
checkReady;
lvConfigFiles := FINIFile.ReadString('main', 'beanConfigFiles', '');
if lvConfigFiles <> '' then
begin
if FTraceLoadFile then
__beanLogger.logMessage('从配置文件中加载bean配置', 'LOAD_TRACE_');
if checkInitializeFromConfigFiles(lvConfigFiles) > 0 then
begin
if FINIFile.ReadBool('main', 'loadOnStartup', False) then
begin
//加载DLL文件, 把DLL载入
checkInitializeFactoryObjects;
end;
end else
begin
if FTraceLoadFile then
__beanLogger.logMessage('没有加载任何配置文件', 'LOAD_TRACE_');
end;
end else
begin
if FTraceLoadFile then
__beanLogger.logMessage('直接加载DLL文件', 'LOAD_TRACE_');
executeLoadLibrary;
end;
end;
end;
插件配置文件命名:主程序名+'.config.ini' 或 app.config.ini 。
如果存在配置文件,则FTraceLoadFile := True,否则FTraceLoadFile :=False;
1.3 官方资源
MyBean 由 D10.天地弦(QQ:185511468)开发。
官方Blog: http://www.cnblogs.com/DKSoft/
官方网站: www.diocp.org
讨论QQ群: 205486036 (MyBean轻量级配置框架)
MyBean的源码库: https://git.oschina.net/ymofen/delphi-framework-MyBean
转:认识MyBean的更多相关文章
- 转:MyBean的安装
1.下载MyBean源码包.可以到https://git.oschina.net/ymofen/delphi-framework-MyBean下载Zip压缩包,也可以用Git客户端下载. 2.将框架源 ...
- 转:MyBean简介
(在开始之前,非常感谢 D10.天地弦) 1.1 概述 MyBean是一个用于Delphi应用程序开发的开源.轻量级.可配置插件框架.它通过巧妙的系统架构设计, ...
- [MyBean-插件]MyBean通用报表免费无限制版本发布
[优点] 1.开发时无需安装报表组件(可以直接用编译好的文件,注意版权说明,请自行编译一次相应的报表插件文件). 2.无带包烦恼所有版本Delphi都可以使用,不拖累Delphi版本的 ...
- MyBean通用报表插件介绍
特性: 1.基于MyBean插件平台.可以在任何插件中无缝调用显示. 2.其他窗体中无需引用报表控件.就可以拥有报表的设计预览打印等功能. 3.甚至可以不用带包,制作报表插件,也就是说你可以将RM的报 ...
- 【MyBean调试笔记】关于单元的释放顺序
[概述] DEMO提交人:惠商软件 2508696439 问题描述:MDIConsole, DEMO如果Forms单元引用顺序放在mybean.console.pas文件之后如下图所示时: 创建同一 ...
- MyBean 框架入门手册<感谢[青铜]整理的如此细致和系统>
MyBean 框架入门手册 2014/9/15 by lighttop 目 录 MyBean 框架学习笔记............................................... ...
- [DIOCP3/MyBean/QDAC开源项目] DataModule-DB例子基于MyBean的插件实例<三层数据库方案>
[说明] 这个例子答应大家很久了,一直没有时间弄,现在正式结合MyBean插件可以很方便的在客户端共享操作连接,执行数据库的各项工作,屏蔽了底层的通信解码器编码等工作,直接传递Variant,给了开发 ...
- [MyBean说明书]-如何进行最简单的DEMO
MyBean是轻量级的.绿色的框架,不需要安装任何的组件和携带任何的其他文件,前 期步骤已经相当精简了,仔细阅读完下面简单的五个步骤,就可以编写基于MyBean的插件: 1.加入Delphi的搜索路径 ...
- [开源项目-MyBean轻量级配置框架] 使用MyBean快速搭建分模块的应用程序(主页面的TAB)(DLL-MDI)
[概述] 抱歉由于上次开源比较匆忙,没有来的及做一个DEMO,里面也有些垃圾的文件没有及时清理.DEMO其实昨天晚上已经调通.相关说明文档今天晚上才说明好,欢迎大家继续关注和交流,和大家一起分享我10 ...
随机推荐
- iOS 标识
通常情况下,iOS系统用NSUserDefaults存储数据信息,但是对于一些私密信息,比如密码.证书等等,就需要使用更为安全的keychain了. keychain里保存的信息不会因App被删除而丢 ...
- 基于params,ref,out的参数问题详解
http://www.jb51.net/article/37967.htm 最近在写程序时遇到params,ref,out 参数问题.回头有自习看了看MSDN,才巩固了基础.现在和大家分享一下.par ...
- java1234教程系列笔记 S1 Java SE chapter 02 写乘法口诀表
一.水仙花数 1.方式一:这是我的思路,取各个位数的方式.我个人习惯于使用取模运算. public static List<Integer> dealNarcissiticNumberMe ...
- Inventor 2014 sp1/sp2激活
问题: win8.1 inventor2014,不打补丁不兼容: 打了补丁xforce激活始终无法成功. 解决: 1. 使用未打补丁之前的 adlmact.dll 和 adlmact_libFNP.d ...
- Window 消息大全
消息,就是指Windows发出的一个通知,告诉应用程序某个事情发生了.例如,单击鼠标.改变窗口尺寸.按下键盘上的一个键都会使Windows发送一个消息给应用程序. 消息本身是作为一个记录传递给应用程序 ...
- 实践总结 - 不可错过的Angular应用技巧
angular的核心思想是通过数据驱动一切,其他东西都是数据的延伸. 套用Javascript一切皆对象的思想,在angular中可以说一切皆数据. 关于项目构建 (1) requirejs以及Yeo ...
- http 301 和 302 的区别!
1.什么是301转向?什么是301重定向? 301转向(或叫301重定向,301跳转)是当用户或搜索引擎向网站服务器发出浏览请求时,服务器返回的HTTP数据流中头信息(header)中的状态码的一种, ...
- linux使用secureCRT连接(没有rsa的时候)
一台linux新机器,怎么使用secureCRT连接呢??? 首先 vim /etc/sysconfig/network-scripts/ifcfg-eth0 把BOOTPROTO=none I ...
- DHTMLX-Form
DHTMLX-Form dhtmlxForm提供了一个标准形式与一些有用的补充,如不同风格,使用的数据从客户端和服务器端,与其他dhtmlx组件的集成.验证等. 例子 <!DOCTYPE htm ...
- Android学习笔记(十三)
Android中的广播机制 Android提供了一套完整的API,允许应用程序自由地发送和接受广播. 发送广播的方法借助于Intent,接受广播的方法需要广播接收器(BroadcastsReceive ...