專案尾聲需補充日誌功能,傳統做法在每個 Action 執行處手寫 FLog.LogCommand('...'),二十餘處重複程式碼讓開發者陷入「複製貼上」泥沼,違反 DRY 原則,維護成本極高。
AOP 核心為橫切關注點分離:將通用功能(日誌、效能監控、權限檢查)從業務邏輯中抽離,在「切點」統一織入。Delphi 雖無原生 AOP 框架,但事件機制可模擬「方法攔截」:
TAction.OnExecute 事件。type
TActionHook = class
private
FActionList: TList;
FActionEvents: array of TNotifyEvent;
FLog: ILog;
procedure HookActionExecute(Sender: TObject);
procedure DoBeforeActionExecute(Action: TAction);
procedure DoAfterActionExecute(Action: TAction);
public
constructor Create(ALog: ILog);
procedure RegisterAction(Action: TAction);
destructor Destroy; override;
end;
procedure TActionHook.RegisterAction(Action: TAction);
begin
FActionList.Add(Action);
SetLength(FActionEvents, Length(FActionEvents) + 1);
FActionEvents[High(FActionEvents)] := Action.OnExecute; // 保存原始事件
Action.OnExecute := HookActionExecute; // 偷換事件
end;
procedure TActionHook.HookActionExecute(Sender: TObject);
var idx: Integer;
begin
DoBeforeActionExecute(TAction(Sender));
idx := FActionList.IndexOf(Sender);
if Assigned(FActionEvents[idx]) then
FActionEvents[idx](Sender); // 執行原始業務邏輯
DoAfterActionExecute(TAction(Sender));
end;
procedure TActionHook.DoAfterActionExecute(Action: TAction);
begin
FLog.LogCommand(Action.Caption); // 統一日誌:以 Action.Caption 為操作描述
end;
系統啟動時,遍歷所有表單的 TAction 元件,逐一 RegisterAction。業務程式碼零修改,日誌自動生效。
DoBeforeActionExecute 可加入權限檢查、效能計時;支援擴展至 TButton.OnClick 等其他事件型別。「體力活」往往隱藏著架構改良契機。善用語言特性(事件、介面、泛型)實踐 AOP 核心思想,能以最小成本解決橫切關注點,讓程式碼乾淨、可維護、可演進。