国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Delphi > 正文

代碼重構(gòu)——之獲得封裝性DELPHI編碼實例

2019-11-18 18:32:28
字體:
供稿:網(wǎng)友
代碼重構(gòu)——之獲得封裝性DELPHI編碼實例
 
代碼重構(gòu)是獲得結(jié)構(gòu)良好的方法,通過重構(gòu),我們在保持功能不變的情況下,改善代碼的質(zhì)量,提高代碼的復(fù)用程度。下面是一個獲得改善代碼質(zhì)量和獲得封裝性的一個具體的例子。(例子使用DELPHI)
代碼功能:
       給數(shù)據(jù)集設(shè)(TClientDataSet)置過濾器,用戶可以在一個TComboBox中選擇要過濾的字段,然后在一個Tedit框中輸入要過濾的值。如圖一:
最常見的做法就是在TComboBox的Items屬性中硬碼寫入我們數(shù)據(jù)集中的字段名稱,然后在代碼中加入一大堆case或者if語句在判斷用戶選擇的字段來給數(shù)據(jù)集設(shè)置過濾器。
……
      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
……
這樣的代碼通過硬碼同樣也實現(xiàn)了這個給數(shù)據(jù)集設(shè)置過濾器的功能,滿足了需求,但是上面這段代碼是不靈活的。如果數(shù)據(jù)集的字段很多就要求編碼人員一個一個字段錄入在Items中,而且在寫case必須核對好順序,不然設(shè)置的過濾器就是錯誤的也就很容易由開發(fā)人員引入BUG。用if語句時也一樣維護(hù)一個大量的if同樣是痛苦的,而且不支持需求變化,當(dāng)用戶要求改變數(shù)據(jù)集字段的中文顯示名稱時必須也要記住更改TComboBox. Items中的硬碼數(shù)據(jù),如果一旦忘記就會引入BUG。
 
于是我在第一次重構(gòu)中,嘗試動態(tài)的加載TComboBox. Items中的數(shù)據(jù),同時為了實現(xiàn)加載后用戶選擇時實現(xiàn)對照。我在這個查詢FORM中加了一個 私有FFields: array[0..20, 0..2] of string; 字段來保存數(shù)據(jù)集中的字段信息數(shù)據(jù)。同時實現(xiàn)了一個加載數(shù)據(jù)的過程:
 
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;
 
這樣就實現(xiàn)了在運行時動態(tài)加載字段信息。這樣我的過濾器設(shè)置就變成了這樣的。
 
if ComboBox1.Text <> '' then
begin
ClientDataSet.Filtered := False;
    ClientDataSet.Filter := FFields[ComboBox1.ItemIndex, 0] +  '''' + Edit2.Text + '''';
       ClientDataSet.Filtered := True;
end;
 
本方法無疑增加了代碼的靈活性,同時增加了代碼的復(fù)用度,因為代碼很好的隔離了變化的數(shù)據(jù)。因此只要在另一個也是要實現(xiàn)這種的功能的FORM中增加私有字段FFields: array[0..20, 0..2] of string 和使用上面的動態(tài)加載數(shù)據(jù)集字段過程,就可以說方便的實現(xiàn)了重用。但是這種重用并不是很好的,因為我們沒有實現(xiàn)很好的封裝性。導(dǎo)致在你的程序中到處散落有重復(fù)的代碼(你常常會通過COPY來獲得這個函數(shù)的重用,因為上面的代碼是沒有好的封裝性)。如果有一天你要修改數(shù)據(jù)裝載函數(shù)你就必須到處去找那里拷貝了該函數(shù)——你也得修改散落在其他地方的代碼。于是我進(jìn)行了再一次的重構(gòu),并對代碼進(jìn)行了進(jìn)一步的封裝。
代碼如下:
unit uDataSetFieldsInfo;
// Description:單元包括 TDataSetFieldsInfo 類,該類封裝了獲得數(shù)據(jù)集子段信息。
// 并提供了在combobox列表顯示字段顯示信息和獲得對應(yīng)子段名稱的方法接口
// 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 封裝了與實現(xiàn)本文所述功能相關(guān)的數(shù)據(jù)和方法,把它們封裝在一個類里面,從而實現(xiàn)了面向?qū)ο笤O(shè)計里面的 Open - Close 原則。類變成了一個黑盒,于是就可方便的重用(black-box reuse),而不必?fù)?dān)心代碼的重復(fù)。同時因為封裝了與功能相關(guān)的信息,類的職責(zé)定義明確(單職責(zé)),并有了足夠合適的粒度和好的封裝性。TdataSetFieldsInfo 很好的把組合框與變化的數(shù)據(jù)隔離開來,最終提高了代碼的復(fù)用程度,同時減少了FORM類的職責(zé)和 magic number硬編碼的量。下面是新的代碼:
首先在FORM中聲明TdataSetFieldsInfo類的一個引用。
……
在FORM創(chuàng)建的時候調(diào)用:
FFieldsInfo := TDataSetFieldsInfo.Create;
FFieldsInfo.GetDataSetFields(cdMaster);
FFieldsInfo.ShowFieldsInfo(ComboBox1);
這時候我的過濾器設(shè)置就變成了:
if ComboBox1.Text <> '' then
begin
ClientDataSet.Filtered := False;
    ClientDataSet.Filter := FFieldsInfo.GetFieldsNameByDisplayLabel(ComboBox1.Text) +  '''' + Edit2.Text + '''';
       ClientDataSet.Filtered := True;
end;
 
通過調(diào)用FfieldsInfo對象的接口過程來獲得對應(yīng)的子段名稱。
 
本文是一個重構(gòu)代碼的簡單例子,我想上面我實現(xiàn)的這個類還可以有很多種寫法和更好的算法。這里只是提供一種關(guān)于重構(gòu)代碼的思路,為提高我們的編寫代碼質(zhì)量和它的可維護(hù)性、擴展性,探討OOD編程方式上的思路。

上一篇:Delphi代碼創(chuàng)建形式規(guī)范

下一篇:在Delphi中自己建立交叉表

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
學(xué)習(xí)交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網(wǎng)友關(guān)注

主站蜘蛛池模板: 富裕县| 长海县| 台湾省| 黎平县| 日土县| 屯留县| 平果县| 云安县| 北碚区| 仁怀市| 衡东县| 广平县| 丹凤县| 保德县| 中阳县| 吐鲁番市| 阜康市| 通海县| 洛隆县| 新蔡县| 赫章县| 邢台市| 崇义县| 新闻| 尚义县| 仪征市| 五寨县| 华宁县| 周宁县| 枣强县| 高台县| 灵宝市| 根河市| 庆云县| 娱乐| 扎赉特旗| 将乐县| 镇平县| 突泉县| 四平市| 汝城县|