Inversion Of Control(IoC)其实并不神秘,它实际上是软件的一种设计原则,即Bob大叔提出的依赖倒置原则(Dependency Inversion Principle, DIP),简单来说就是“面向抽象编程”。那为什么要面向抽象而不直接依赖具体类呢?我们先看一个使用信用卡付款的例子:
// TPaymentManager类封装了所有付款方式的操作
procedure TPaymentManager.PayByCreditCard(amount: Currency);
var
cardNo: string;
begin
cardNo := WaitForCreditCardNo; // 创建另一窗体,等待输入信用卡卡号
TCreditCardService.GetInstance.Withdraw(cardNo, amount * 0.7); // 单例模式
end;
在上面的示例程序中,TPaymentManager类直接使用了TCreditCardService类的唯一实例,并调用其Withdraw方法完成信用卡的付款。这段代码虽然简单,但也暴露出了依赖具体类所存在的严重问题:
1. 不可测试性
在上面的这个例子中,依赖具体类的结果是必须刷真正的信用卡才可以测试业务逻辑是否正确。
2. 无法模拟异常
这是上一个问题的副作用,如果依赖具体类,我们就不能模拟所有的业务异常,也无法判断软件是否能正确处理所有异常。
3. 不便于重用
很显然,如果依赖具体类,不仅TPaymentManager不能重用,就连TCreditCardService都可能无法重用,因为它可能也依赖某种具体的通讯协议或某种固定的硬件。
转眼间已经步入了12月份,此时再回顾上个月的工作计划,真的觉得太宏伟了。不过好在经过上个月的开发,我已经大致掌握了项目的开发节奏。
这段时间大家反映比较多的是目前spring没有相关的开发文档,想学习和使用这个框架非常困难。的确如此。我准备这段时间放慢新特性的开发节奏,把主要精力放到开发文档和完善代码质量上面。本月的主要任务有:
现在时刻:北京时间2009年11月1日00点07分。
这几天很多人问我:“Delphi Spring Framework的定位是什么?“,”这个框架和其他平台上的spring框架有什么不同?“。于是我抽时间把自己的想法整理了一下,并画了一张架构图:

这就是我目前对spring框架的规划,整个构想包含三个层面:
1. 基础类库(Base Class Library)
2. 核心类库(Core Library)
3. 扩展应用框架(Extensions)
至今我还记得当Allen Bauer首次演示Live Templates的时候台下响起了长时间的掌声——因为LiveTemplates实在太棒了!
究竟什么是Live Templates呢?其实是预先定义好一些可重复使用的代码片段(xml文件格式),当在代码编辑器里面输入对应的热键的时候就会生成对应的代码片段,以减少输入。与众不同的是,编辑器会自动进入SyncEdit(同步编辑)模式,并可按Tab键(或Shift-Tab)跳转输入焦点,还可以结合class completion和block completion来自动生成代码,非常灵活。 不多说了,大家先看看下面的演示吧:

Delphi Spring Framework编程规范(草稿)V0.1 (更新日期:2009-10-28)
1. 前言
为保证Delphi Spring Framework项目代码的可读性和质量,特建立本编程规范。本规范仅适用于Delphi Spring Framework各项目成员,大家如有任何意见和建议,请给我留言。
我考虑了很久,还是决定先把代码发布出来,早点接受大家的反馈。
Delphi Spring Framework的目标是为企业应用程序提供强劲而灵活的基础架构。整个框架基于Embarcadero RAD Studio 2010平台,充分利用了新的语言特性(如泛型、匿名方法和反射),并借鉴了.net和java平台上其他同类框架的一些思想,希望能给大家带来全新的体验。
Posted on : 2009-10-12 | By : Paul | In : 生活点滴
0
记得读书的时候有一次跑去旁听艺术设计课,老师让我们发挥想象力——造字:无论是单个汉字,还是描述故事都可以。刚好之前我听马哲老师讲了一个小故事,没想到一下子就派到用场了,呵呵,看看偶当时的作品吧:
你猜猜看,这是什么故事?(答案在下面)
Posted on : 2009-07-10 | By : Paul | In : Delphi
5
【更新日期:2009-11-04】最新版本发布在Delphi Spring Framework项目中的Spring.System.pas。
昨天我看到.Net里面有一个DriveInfo类,可以获得系统所有的磁盘状态和信息。我就忍不住把它移植到了Delphi里面,并放到Delphi Spring Project里面准备一起发布。
大家先看看TDriveInfo的使用方式:
procedure TForm1.FormCreate(Sender: TObject);
var
drive: TDriveInfo;
begin
for drive in TDriveInfo.GetDrives do
with Memo1.Lines do
begin
if drive.IsReady then
begin
Add(Format('Name: %s', [drive.Name]));
Add(Format('AvailableFreeSpace: %d', [drive.AvailableFreeSpace]));
Add(Format('TotalFreeSpace: %d', [drive.TotalFreeSpace]));
Add(Format('TotalSize: %d', [drive.TotalSize]));
Add(Format('DriveFormat: %s', [drive.DriveFormat]));
Add(Format('DriveType: %s', [drive.DriveTypeString]));
Add(Format('VolumeLabel: %s', [drive.VolumeLabel]));
end
else
begin
Add(Format('Drive %s is not ready', [drive.Name]));
end;
end;
end;
下面是完整的实现代码:
Posted on : 2009-06-12 | By : Paul | In : Delphi
2
【更新日期:2009-11-04】最新版本发布在Delphi Spring Framework项目中的Spring.System.pas。
相信各位Delphier都知道,伴随Delphi 2009的发布,Delphi又丰富了很多语言特性,比如:Unicode、Generics(泛型)和Anonymous Methods(匿名方法)。下面是我整理的几个常用的匿名方法,和传统的方法相比,能减少不少重复代码,顺便一起分享给大家。
// 锁定同步对象,保证线程安全
procedure Lock(obj: TObject; proc: TProc); inline;
// 批量更新TStrings
procedure UpdateStrings(strings: TStrings; proc: TProc<TStrings>);
// 遍历TDataSet
procedure EnumerateDataSet(dataSet: TDataSet; proc: TProc<TDataset>);
// 按照Tab-Order顺序递归遍历子控件
procedure EnumerateControls(parentControl: TWinControl; proc: TProc<TWinControl>);
操作代码演示:
procedure Test;
var
strings: TStrings;
begin
strings := TStringList.Create;
try
Lock(strings,
procedure
begin
// manipute strings in thread-safe
end
);
UpdateStrings(strings,
procedure(strings: TStrings)
begin
strings.Add('A');
strings.Add('B');
strings.Add('C');
end
);
finally
strings.Free;
end;
end;
在Delphi中GUID(Global Unique Identifier)是用TGUID记录结构来表示:
PGUID = ^TGUID;
TGUID = packed record
D1: LongWord;
D2: Word;
D3: Word;
D4: array[0..7] of Byte;
end;
虽然SysUtils单元封装了一些常见的操作函数(CreateGUID,GUIDToString,StringToGUID,IsEqualGUID),但实际使用时总觉得不是很方便。所幸的是在Delphi 2007及以上的编译器支持Record Helper,所以我重新封装了一下,在Record Helper的帮助下,就可以使用更加OO的方式来操作TGUID了: