业务逻辑与界面元素分离的一次小尝试

项目中有一个需求,为单据的表头增加自定义项。受制于现在的架构和表头布局自定义的实现机制,自定义项的内容只能预先在IDE里面创建好,而不能通过代码动态创建,只好在单据基类里面预先放入一组控件。由于自定义项本身需要提供编辑、参照、配置、读取与保存等操作,而基类本身已经臃肿不堪,接这个机会尝试一次界面与业务逻辑分离的尝试。因为架构中本身没有数据访问曾的设计和实现,而这个仅仅是作为一个尝试,因此控制类里面并没有对数据访问这块进行分离。类图如下:

单据表头自定义项控制类

因为自定义项目前支持的是3个,所以定义了一个常量来描述自定义项的个数,以后如果有扩充,修改这个常量即可。

详细代码如下:

  1 {
  2   该类用于控制单据表头自定义项。
  3   created by fhying@2012.05.04
  4 }
  5 unit BillTitleCustomItemClass;
  6 
  7 interface
  8 
  9 uses
 10   SysUtils, Classes, Controls, Variants, Dialogs, DB, DBClient, cxEdit, cxDBEdit,
 11   Forms, Messages;
 12 
 13 const
 14   Const_BillTitleCustomItem_MAX = 3;
 15 
 16 type
 17   TBillTitleCustomItem = record
 18         itemindex : Integer; {自定义项序号(1-3)}
 19         itemtype : Integer; {自定义项类型(0编辑、1参照)}
 20         itemdatasource : string; {参照的话,数据来源(目前考虑的是基本信息表,如附加说明)}
 21         itemdatafield : string; {参照的话,数据来源的字段}
 22   end;
 23   TBillTitleCustomItems = array[1..Const_BillTitleCustomItem_MAX] of TBillTitleCustomItem;
 24 
 25   TBillTitleCustomItemClass = class(TComponent)
 26   private
 27     FcdsSQL : TClientDataSet;
 28     FBillType: Integer;
 29     FBillTitleCustomItems : TBillTitleCustomItems;
 30     FBillTitleCustomDataSource: TDataSource;
 31     function GetBillTitleCustomItems: TBillTitleCustomItems;
 32     procedure SetBillTitleCustomDataSource(const Value: TDataSource);
 33   protected
 34     { 根据索引获取自定义项的编辑组件 }
 35     function GetButtonEdit(AItemIndex : Integer) : TcxDBButtonEdit; virtual;
 36     { 初始化自定义项内容 }
 37     procedure InitBillTitleCustomItems;
 38     { 创建cds,用于执行sql语句 }
 39     procedure CreateCDS;
 40     { 保存自定义项配置到数据库 }
 41     function SaveBillTitleCustomItems(AItemIndex : Integer = 0) : Boolean;
 42     { 从数据库读取自定义项配置 }
 43     procedure LoadBillTitleCustomItems;
 44     { 为自定义项编辑组件进行事件绑定 }
 45     procedure BindcxButtonEdits(AItemIndex : Integer = 0); virtual;
 46     { 绑定自定义项组件的按钮单击事件 }
 47     procedure PropertiesButtonClick(Sender: TObject; AButtonIndex: Integer);
 48     { 执行自定义项编辑组件的参照功能 }
 49     procedure Reference(AItemIndex : Integer);
 50     { 打开自定义项的配置界面 }
 51     procedure CustomConfig(AItemIndex : Integer);
 52     { 绑定数据源 }
 53     procedure SetEditDataSource;
 54   public
 55     { 自定义构造函数,传入单据类型。 }
 56     constructor CreateMy(AOwnerForm : TComponent; ABillType : Integer); virtual;
 57     destructor Destroy; override;
 58     { 对外部调用者公布自定义项配置内容 }
 59     property BillTitleCustomItems : TBillTitleCustomItems read GetBillTitleCustomItems;
 60     { 外部调用者给对象设置数据源 }
 61     property BillTitleCustomDataSource : TDataSource read FBillTitleCustomDataSource write SetBillTitleCustomDataSource;
 62   end;
 63 
 64 implementation
 65 
 66 uses BillTitleCustomItemForm, un_DM, un_ShowForm, Main, PDWizard,
 67   BaseBillA, ProdDw, un_ToolsLC;
 68 
 69 { TBillTitleCustomItemClass }
 70 
 71 procedure TBillTitleCustomItemClass.BindcxButtonEdits(AItemIndex : Integer);
 72 var
 73   i : Integer;
 74   procedure BindcxButtonEdit(AItemIndex : Integer);
 75   var
 76     AItemType : Integer;
 77     AEdit : TcxDBButtonEdit;
 78   begin
 79     AItemType := FBillTitleCustomItems[AItemIndex].itemtype;
 80     AEdit := GetButtonEdit(AItemIndex);
 81     if AEdit = nil then
 82       Exit;
 83     case AItemType of
 84     0 : { 编辑 }
 85       begin
 86         AEdit.Properties.Buttons[0].Visible := False;
 87         AEdit.Properties.ReadOnly := False;
 88       end;
 89     1 : { 参照 }
 90       begin
 91         AEdit.Properties.Buttons[0].Visible := True;
 92         AEdit.Properties.ReadOnly := True;      
 93       end;
 94     end;
 95     { 用tag来标记是哪个自定义项 }
 96     AEdit.Tag := AItemIndex;
 97     { 与内置事件绑定 }
 98     AEdit.Properties.OnButtonClick := PropertiesButtonClick;
 99   end;
100 begin
101   if AItemIndex = 0 then
102   begin
103     for i := 1 to Const_BillTitleCustomItem_MAX do
104     begin
105       BindcxButtonEdit(i);
106     end;
107   end
108   else
109   begin
110     BindcxButtonEdit(AItemIndex);
111   end;
112 end;
113 
114 procedure TBillTitleCustomItemClass.CreateCDS;
115 begin
116   if FcdsSQL = nil then
117   begin
118     FcdsSQL := TClientDataSet.Create(nil);
119     FcdsSQL.RemoteServer := DM.Con_SubWork;
120     FcdsSQL.ProviderName := 'dsp_Oper';
121   end;
122 end;
123 
124 constructor TBillTitleCustomItemClass.CreateMy(AOwnerForm: TComponent;
125   ABillType: Integer);
126 begin
127   inherited Create(AOwnerForm);
128   FBillType := ABillType;
129   InitBillTitleCustomItems;
130   LoadBillTitleCustomItems;
131   BindcxButtonEdits;
132 end;
133 
134 procedure TBillTitleCustomItemClass.CustomConfig(AItemIndex : Integer);
135 var
136   frmBillTitleCustomItem: TfrmBillTitleCustomItem;
137 begin
138   frmBillTitleCustomItem := TfrmBillTitleCustomItem.Create(Application);
139   with frmBillTitleCustomItem do
140   begin
141     try
142       ItemType := FBillTitleCustomItems[ItemIndex].itemtype;
143       ShowModal;
144       if ModalResult = mrOK then
145       begin
146         FBillTitleCustomItems[AItemIndex].itemtype := ItemType; // 现在只能设置类型。
147         if SaveBillTitleCustomItems(AItemIndex) then
148         begin
149           { 保存前,已经更新了本地变量,所以不需要再从数据库获取一次。及时性要求不需要这样高。 }
150           {LoadBillTitleCustomItems;}
151           BindcxButtonEdits(AItemIndex);
152         end;
153       end;
154     finally
155       Free;
156     end;
157   end;
158 end;
159 
160 destructor TBillTitleCustomItemClass.Destroy;
161 begin
162   if FcdsSQL <> nil then
163   begin
164     FcdsSQL.Close;
165     FcdsSQL.Free;
166   end;
167   inherited;
168 end;
169 
170 function TBillTitleCustomItemClass.GetBillTitleCustomItems: TBillTitleCustomItems;
171 begin
172   Result := FBillTitleCustomItems;
173 end;
174 
175 function TBillTitleCustomItemClass.GetButtonEdit(
176   AItemIndex: Integer): TcxDBButtonEdit;
177 var
178   AEditName : string;
179   AEdit : TComponent;
180 begin
181   AEditName := 'edtBillTitleCustomItem' + IntToStr(AItemIndex);
182   AEdit := TForm(Owner).FindComponent(AEditName);
183   if (AEdit <> nil) and (AEdit is TcxDBButtonEdit) then
184     Result := TcxDBButtonEdit(AEdit)
185   else
186     Result := nil;
187 end;
188 
189 procedure TBillTitleCustomItemClass.InitBillTitleCustomItems;
190 var
191   i : Integer;
192 begin
193   for i := 1 to Const_BillTitleCustomItem_MAX do
194   begin
195     FBillTitleCustomItems[i].itemindex := i;
196     FBillTitleCustomItems[i].itemtype := 0;
197     FBillTitleCustomItems[i].itemdatasource := 'commoninfo';
198     FBillTitleCustomItems[i].itemdatafield := 'u_Remark';
199   end;
200 end;
201 
202 procedure TBillTitleCustomItemClass.LoadBillTitleCustomItems;
203 begin
204   CreateCDS;
205   FcdsSQL.CommandText :=
206     'select * from BillTitleCustomItem where billtype = '+IntToStr(FBillType)+' order by ItemIndex';
207   FcdsSQL.Open;
208   with FcdsSQL do
209   begin
210     if RecordCount > Const_BillTitleCustomItem_MAX then
211     begin
212       Exit;
213     end;
214     First;
215     while not Eof do
216     begin
217       FBillTitleCustomItems[RecNo].itemindex := FieldByName('ItemIndex').AsInteger;
218       FBillTitleCustomItems[RecNo].itemtype := FieldByName('itemtype').AsInteger;
219       FBillTitleCustomItems[RecNo].itemdatasource := FieldByName('itemdatasource').AsString;
220       FBillTitleCustomItems[RecNo].itemdatafield := FieldByName('itemdatafield').AsString;
221 
222       Next;
223     end;
224   end;
225 end;
226 
227 procedure TBillTitleCustomItemClass.PropertiesButtonClick(Sender: TObject;
228   AButtonIndex: Integer);
229 begin
230   case AButtonIndex of
231   0 : Reference(TcxDBButtonEdit(Sender).Tag);
232   1 : CustomConfig(TcxDBButtonEdit(Sender).Tag);
233   end;
234 end;
235 
236 { 因为现在这里只是针对进货单和销售单,且参照仅针对附加说明,所以先这样处理。 }
237 procedure TBillTitleCustomItemClass.Reference(AItemIndex : Integer);
238 var
239   szFieldName : string;
240 begin
241   if tclientdataset(BillTitleCustomDataSource.DataSet).ReadOnly then
242     Exit;
243 
244   fm_main.vpSingleType := 13;
245 
246   fm_ProdDw := Tfm_ProdDw.create(application);
247   try
248     with fm_ProdDw do
249     begin
250       fm_ProdDw.vpCalltype := 3;
251 
252       T1_Showmodal(fm_ProdDw);
253       if modalresult = mrok then
254       begin
255         szFieldName := 'Item' + IntToStr(AItemIndex);
256         tclientdataset(BillTitleCustomDataSource.DataSet).Edit;
257         tclientdataset(BillTitleCustomDataSource.DataSet).FieldByName(szFieldName).AsString := cds_SingleList.FieldByName('U_Remark').AsString;
258         tclientdataset(BillTitleCustomDataSource.DataSet).Post;
259       end;
260     end;
261   finally
262     gl_Trans.Info1 := '';
263     fm_ProdDw.free;
264   end;
265 end;
266 
267 function TBillTitleCustomItemClass.SaveBillTitleCustomItems(AItemIndex : Integer): Boolean;
268 var
269   szSQL : string;
270   function MakeSaveSQL : string;
271   var
272     i : Integer;
273     szDelete : string;
274     szTmp : string;
275   begin
276     Result := '';
277     if AItemIndex = 0 then
278     begin
279       szDelete := ' delete from BillTitleCustomItem where BillType = '+IntToStr(FBillType);
280 
281       for i := 1 to Const_BillTitleCustomItem_MAX do
282       begin
283         szTmp := ' insert into BillTitleCustomItem (BillType, itemindex, itemtype, itemdatasource, itemdatafield) values (%d,%d,%d,'+Char(39)+'%s'+Char(39)+','+Char(39)+'%s'+Char(39)+')';
284         with FBillTitleCustomItems[i] do
285           szTmp := Format(szTmp, [FBillType, itemindex, itemtype, itemdatasource, itemdatafield]);
286 
287         Result := Result + szTmp ;//+ Char(13)+Char(10);
288       end;
289     end
290     else
291     begin
292       szDelete := ' delete from BillTitleCustomItem where BillType = '+IntToStr(FBillType) + ' and itemindex =' + IntToStr(AItemIndex);
293       szTmp := ' insert into BillTitleCustomItem (BillType, itemindex, itemtype, itemdatasource, itemdatafield) values (%d,%d,%d,'+Char(39)+'%s'+Char(39)+','+Char(39)+'%s'+Char(39)+')';
294       with FBillTitleCustomItems[AItemIndex] do
295         szTmp := Format(szTmp, [FBillType, AItemIndex, itemtype, itemdatasource, itemdatafield]);
296       Result := Result + szTmp ;
297     end;
298 
299     Result := szDelete + Result;
300   end;
301 begin
302   szSQL := MakeSaveSQL;
303   FcdsSQL.CommandText := szSQL;
304   try
305     FcdsSQL.Execute;
306 
307     Result := True;
308   except
309     on e : Exception do
310     begin
311       Result := False;
312       ShowDlg(1, '保存单据表头自定义项设置失败。'+#13+'错误信息:'+#13+e.Message);
313     end;
314   end;
315 end;          
316 
317 procedure TBillTitleCustomItemClass.SetBillTitleCustomDataSource(
318   const Value: TDataSource);
319 begin
320   FBillTitleCustomDataSource := Value;
321   SetEditDataSource;
322 end;
323 
324 procedure TBillTitleCustomItemClass.SetEditDataSource;
325 var
326   i : Integer;
327   AEdit : TcxDBButtonEdit;
328 begin
329   for i := 1 to Const_BillTitleCustomItem_MAX do
330   begin
331     AEdit := GetButtonEdit(i);
332     AEdit.DataBinding.DataSource := BillTitleCustomDataSource;
333     AEdit.DataBinding.DataField := 'Item'+IntToStr(i);
334   end;
335 end;
336 
337 end.

此外,对于多账户支付的功能,我也用类似的思路设计了一个类,但是感觉里面比较紊乱,应该能够分得更清晰,降低耦合,增强内聚。请达者指教。谢谢。

多账户支付控制类

原文地址:https://www.cnblogs.com/codingnote/p/2491373.html