• [转]解耦:Delphi下IoC 模式的实现


    解耦:Delphi下IoC 模式的实现

    摘要:在Delphi下IoC模式的多种实现

    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.

  • 相关阅读:
    spring 配置 线程池并使用 springtest 进行测试
    Mybatis使用generator自动生成的Example类使用OR条件查询
    springtest mapper注入失败问题解决 {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    异常 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found) 解决方案
    idea 开启 tomcat 访问日志记录
    idea ssm项目迁移到另一台机器上时出现不能正常启动项目的解决方案
    记一次 java 连接 linux ssh服务 权限验证失败的原因和解决过程
    ajax传递数组给controller的实现方法和坑
    service手动实例化(new)导致类中的spring对象无法注入的问题解决
    javaweb学习总结十一(JAXP对XML文档进行DOM解析)
  • 原文地址:https://www.cnblogs.com/moon25/p/1600879.html
Copyright © 2020-2023  润新知