分享
 
 
 

代码重构——之获得封装性DELPHI编码实例

王朝delphi·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

代码重构——之获得封装性DELPHI编码实例

代码重构是获得结构良好的方法,通过重构,我们在保持功能不变的情况下,改善代码的质量,提高代码的复用程度。下面是一个获得改善代码质量和获得封装性的一个具体的例子。(例子使用DELPHI)

代码功能:

给数据集设(TClientDataSet)置过滤器,用户可以在一个TComboBox中选择要过滤的字段,然后在一个Tedit框中输入要过滤的值。如图一:

最常见的做法就是在TComboBox的Items属性中硬码写入我们数据集中的字段名称,然后在代码中加入一大堆case或者if语句在判断用户选择的字段来给数据集设置过滤器。

……

case ComboBox1.ItemIndex of

0:

ClientDataSet.Filtered := False;

ClientDataSet.Filter := ' F_CODE = ''' + Edit2.Text + '''';

ClientDataSet.Filtered := True;

1:

ClientDataSet.Filtered := False;

ClientDataSet.Filter := ' F_CHINESE_NAME = ''' + Edit2.Text + '''';

ClientDataSet.Filtered := True;

……

end;

或者用

….…

if ComboBox1.Text = '物料编码' then

begin

ClientDataSet.Filtered := False;

ClientDataSet.Filter := ' F_CODE = ''' + Edit2.Text + '''';

ClientDataSet.Filtered := True;

end

else if ComboBox1.Text = '名称' then

begin

ClientDataSet.Filtered := False;

ClientDataSet.Filter := ' F_CHINESE_NAME = ''' + Edit2.Text + '''';

ClientDataSet.Filtered := True;

end

……

这样的代码通过硬码同样也实现了这个给数据集设置过滤器的功能,满足了需求,但是上面这段代码是不灵活的。如果数据集的字段很多就要求编码人员一个一个字段录入在Items中,而且在写case必须核对好顺序,不然设置的过滤器就是错误的也就很容易由开发人员引入BUG。用if语句时也一样维护一个大量的if同样是痛苦的,而且不支持需求变化,当用户要求改变数据集字段的中文显示名称时必须也要记住更改TComboBox. Items中的硬码数据,如果一旦忘记就会引入BUG。

于是我在第一次重构中,尝试动态的加载TComboBox. Items中的数据,同时为了实现加载后用户选择时实现对照。我在这个查询FORM中加了一个 私有FFields: array[0..20, 0..2] of string; 字段来保存数据集中的字段信息数据。同时实现了一个加载数据的过程:

PRocedure TFrmSPARealStorageQuery.GetQueryFields;

var

i, iFieldsCount: Integer;

begin

iFieldsCount := 0;

with DBGride1.DataSource.DataSet do

begin

for i := 0 to Fields.Count - 1 do

if Fields[i].Visible then

begin

FFields[iFieldsCount, 0] := Fields[i].FieldName;

FFields[iFieldsCount, 1] := Fields[i].DisplayLabel;

Inc(iFieldsCount);

end;

ComboBox1.Items.Clear;

for i := 0 to iFieldsCount - 1 do

ComboBox1.Items.Add(FFields[i, 1]);

end;

end;

这样就实现了在运行时动态加载字段信息。这样我的过滤器设置就变成了这样的。

if ComboBox1.Text <> '' then

begin

ClientDataSet.Filtered := False;

ClientDataSet.Filter := FFields[ComboBox1.ItemIndex, 0] + '''' + Edit2.Text + '''';

ClientDataSet.Filtered := True;

end;

本方法无疑增加了代码的灵活性,同时增加了代码的复用度,因为代码很好的隔离了变化的数据。因此只要在另一个也是要实现这种的功能的FORM中增加私有字段FFields: array[0..20, 0..2] of string 和使用上面的动态加载数据集字段过程,就可以说方便的实现了重用。但是这种重用并不是很好的,因为我们没有实现很好的封装性。导致在你的程序中到处散落有重复的代码(你常常会通过COPY来获得这个函数的重用,因为上面的代码是没有好的封装性)。如果有一天你要修改数据装载函数你就必须到处去找那里拷贝了该函数——你也得修改散落在其他地方的代码。于是我进行了再一次的重构,并对代码进行了进一步的封装。

代码如下:

unit uDataSetFieldsInfo;

// Description:单元包括 TDataSetFieldsInfo 类,该类封装了获得数据集子段信息。

// 并提供了在combobox列表显示字段显示信息和获得对应子段名称的方法接口

// Created : wuchhao

// Date : 2003.5

interface

uses Classes, DBClient, StdCtrls;

type

TDataSetFieldsInfo = class

private

FFieldsList: TStrings;

public

constructor Create;

destructor Destroy; override;

procedure GetDataSetFields(Source: TClientDataSet);

procedure ShowFieldsInfo(Target: TComboBox);

function GetFieldsNameByDisplayLabel(DisplayLabel: string): string;

end;

implementation

{ TDataSetFieldsInfo }

constructor TDataSetFieldsInfo.Create;

begin

FFieldsList := TStringList.Create;

end;

destructor TDataSetFieldsInfo.Destroy;

begin

FFieldsList.Free;

inherited;

end;

procedure TDataSetFieldsInfo.GetDataSetFields(Source: TClientDataSet);

var

i: Integer;

begin

FFieldsList.Clear;

with Source do

begin

for i := 0 to Fields.Count - 1 do

if Fields[i].Visible then

begin

FFieldsList.Add(Fields[i].DisplayLabel);

FFieldsList.Add(Fields[i].FieldName);

end;

end;

end;

function TDataSetFieldsInfo.GetFieldsNameByDisplayLabel(

DisplayLabel: string): string;

var

index: Integer;

begin

Result := '';

index := FFieldsList.IndexOf(DisplayLabel);

if index <> -1 then

Result := FFieldsList.Strings[index+1] ;

end;

procedure TDataSetFieldsInfo.ShowFieldsInfo(Target: TComboBox);

var

i: Integer;

begin

Target.Items.Clear;

i:=0;

while i < FFieldsList.Count do

begin

Target.Items.Add(FFieldsList.Strings[i]);

i:= i+ 2;

end;

end;

end.

单元uDataSetFieldsInfo 封装了与实现本文所述功能相关的数据和方法,把它们封装在一个类里面,从而实现了面向对象设计里面的 Open - Close 原则。类变成了一个黑盒,于是就可方便的重用(black-box reuse),而不必担心代码的重复。同时因为封装了与功能相关的信息,类的职责定义明确(单职责),并有了足够合适的粒度和好的封装性。TdataSetFieldsInfo 很好的把组合框与变化的数据隔离开来,最终提高了代码的复用程度,同时减少了FORM类的职责和 magic number硬编码的量。下面是新的代码:

首先在FORM中声明TdataSetFieldsInfo类的一个引用。

……

在FORM创建的时候调用:

FFieldsInfo := TDataSetFieldsInfo.Create;

FFieldsInfo.GetDataSetFields(cdMaster);

FFieldsInfo.ShowFieldsInfo(ComboBox1);

这时候我的过滤器设置就变成了:

if ComboBox1.Text <> '' then

begin

ClientDataSet.Filtered := False;

ClientDataSet.Filter := FFieldsInfo.GetFieldsNameByDisplayLabel(ComboBox1.Text) + '''' + Edit2.Text + '''';

ClientDataSet.Filtered := True;

end;

通过调用FfieldsInfo对象的接口过程来获得对应的子段名称。

本文是一个重构代码的简单例子,我想上面我实现的这个类还可以有很多种写法和更好的算法。这里只是提供一种关于重构代码的思路,为提高我们的编写代码质量和它的可维护性、扩展性,探讨OOD编程方式上的思路。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有