在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
IOC英文为 Inversion of Control,即反转模式,这里有著名的好莱坞理论:你呆着别动,到时我会找你。Ioc模式是解决调用者和被调用者之间关系的模式,可以有效降低软件的耦合度,并适合团队开发,使用这种模式需要首先设计一个好的框架,也可以称之为IoC容器(可能这样的说法在Java世界更Cool J)。其实Windows内部就存在这样的模式,称之为Callback(回调),在Delphi 的源代码中也有很多这样的方式。看一个例子:
可以打开下面两个文件
$(Delphi)\Source\Vcl\DB.pas
$(Delphi)\Source\Vcl\DBLogDlg.pas
第二个文件是一个需要用户填写登录用户名和密码的对话框,显然这属于用户交互层,
我们不希望在DB.pas(数据逻辑层)中直接调用这个功能,Delphi是这样实现的:
DB.pas #2282 有这样的声明:
LoginDialogProc: function (const ADatabaseName: string; var AUserName, APassword: string): Boolean;
LoginDialogProc 被定义为函数类型变量。
在DBLogDlg.pas #132
initialization
if not Assigned(LoginDialogProc) then LoginDialogProc := LoginDialog;
也就是在DBLogDlg.pas单元初始化阶段给DB.Pas中的LoginDialogProc赋予实现函数。
我觉得这个例子已经足够把问题说得清楚了。
当然这并非实现IoC的唯一方法,对于不同的语言都有自己的特性,上面的方法可能比较古老的一种,通过函数指针来实现,其他的方法还有
一:封装为接口
我们看到在DB.pas 中声明了很多类似的函数变量,我们可以将其封装为一个接口
IDBDlogInterface = Interface
['{06B5DEAC-0BB1-4658-91F6-E78004DF131D}']
LoginDialogProc: function (const ADatabaseName: string; var AUserName, APassword: string): Boolean;
LoginDialogExProc: function (const ADatabaseName: string; var AUserName, APassword: string; NameReadOnly: Boolean): Boolean;
RemoteLoginDialogProc: function (var AUserName, APassword: string): Boolean;
end;
然后申明一个全局的接口类型变量
Var
DBDialog : IDBDialogInterface ;
然后在其他单元实现这个接口,并初始化时赋值到这个接口变量。
二:注册机制的IoC
这个例子稍微复杂一些,但是似乎更使用
我们在一个窗口上放置了一个pageControl,我们知道一个pageControl上可以放置多个pageControl,而且这多个pageControl功能相对独立,没有耦合。我们可以这样做:建立这个主窗体放置一个空的PageControl,然后声明一个TInterfaceList变量用来存储PageControl的具体实现。每一个PageControl动态创建,使用注册的Frame来填充。代码如下:
unit frmStartPage;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ImgList,Contnrs, ComCtrls, ExtCtrls; Type //填充pageControl的Frame基类 TPageFrame = class(TFrame) protected function Caption :String ; virtual; abstract; end; TPageFrameClass = class of TPageFrame ; TStartPage = class(TForm) PageControl1: TPageControl; procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var StartPage :TStartPage ; RegTabSheetClasses: TClassList; procedure RegisterStartPageTabSheet( AFrameClass :TPageFrameClass); implementation {$R *.dfm} procedure TStartPage.FormCreate(Sender: TObject); var i:integer; lTabSheet : TTabSheet; lFrame : TPageFrame; begin for i:= 0 to RegTabSheetClasses.Count -1 do begin lTabSheet := TTabSheet.Create(PageControl1); lFrame := TPageFrameClass( RegTabSheetClasses[i]).Create(self) as TPageFrame; lTabSheet.Caption := lFrame.Caption ; lFrame.Align := alClient; lTabSheet.InsertControl(lFrame); lTabSheet.PageControl := PageControl1; lTabSheet.PageIndex := 0 ; end; end; procedure RegisterStartPageTabSheet( AFrameClass :TPageFrameClass); begin RegTabSheetClasses.Add(AFrameClass); end; initialization RegTabSheetClasses := TClassList.Create ; finalization RegTabSheetClasses.Free; end. unit Unit2; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs,frmStartPage, StdCtrls; type TFrame2 = class(TPageFrame) Label1: TLabel; private { Private declarations } protected { Public declarations } function Caption :String ; override; public end; implementation {$R *.dfm} { TFrame2 } function TFrame2.Caption: String; begin result := 'Frame1'; end; initialization RegisterStartPageTabSheet(TFrame2); end. 转至:http://tb.blog.csdn.net/ |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论