`
禹爸爸
  • 浏览: 80393 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

Delphi VCL Framework中的Action模式

阅读更多

学习过设计模式的人都知道有一种行为模式叫做Command模式。在Delphi的VCL Framework中也使用到了这种模式,那就是Action模式。

命令模式使用的目的在于使用对象来封装客户端的请求命令,由于使用以对象封装,因此可以达到下面的效果:

  • 请求对象可结合多态以及虚拟方法来提供更大的弹性;
  • 负责执行请求的目的对象可以和客户端分离,这就表示多个客户端可以发生相同的请求对象,例如菜单或是工具栏按钮都可以发生打开文件的请求,如此一来菜单和工具栏按钮便可以使用相同的请求对象,而负责打开文件的程序代码并不会绑定到单一的菜单项或是工具栏按钮;
  • 由于使用了请求对象,因此不单是图形用户界面可以触发请求,一般的程序代码也可以通过请求对象来执行特定的工作;
  • 由于请求对象可以使用一个完整的类架构来实现,因此可以让客户端使用一致的程序代码格式来触发各种不同的请求。

实现

在Delphi的Classes单元中提供了Action设计模式的实现类和程序代码。

TBasicAction=class(TComponent)
private
FActionComponent:TComponent;
FOnChange:TNotifyEvent;
FOnExecute:TNotifyEvent;
FOnUpdate:TNotifyEvent;
procedureSetActionComponent(
constValue:TComponent);
protected
FClients:TList;
procedureChange;
virtual;
procedureSetOnExecute(Value:TNotifyEvent);
virtual;
propertyOnChange:TNotifyEventreadFOnChangewriteFOnChange;
procedureNotification(AComponent:TComponent;Operation:TOperation);
override;
public
constructorCreate(AOwner:TComponent);
override;
destructorDestroy;
override;
functionHandlesTarget(Target:TObject):Boolean;
virtual;
procedureUpdateTarget(Target:TObject);
virtual;
procedureExecuteTarget(Target:TObject);
virtual;
functionExecute:Boolean;dynamic;
procedureRegisterChanges(Value:TBasicActionLink);
procedureUnRegisterChanges(Value:TBasicActionLink);
functionUpdate:Boolean;
virtual;
propertyActionComponent:TComponentreadFActionComponentwriteSetActionComponent;
propertyOnExecute:TNotifyEventreadFOnExecutewriteSetOnExecute;
propertyOnUpdate:TNotifyEventreadFOnUpdatewriteFOnUpdate;
end;

...{TBasicAction}

constructorTBasicAction.Create(AOwner:TComponent);
begin
inheritedCreate(AOwner);
FClients:
=TList.Create;
end;

destructorTBasicAction.Destroy;
begin
inheritedDestroy;
ifAssigned(ActionComponent)then
ActionComponent.RemoveFreeNotification(Self);
whileFClients.Count>0do
UnRegisterChanges(TBasicActionLink(FClients.Last));
FreeAndNil(FClients);
end;

functionTBasicAction.HandlesTarget(Target:TObject):Boolean;
begin
Result:
=False;
end;

procedureTBasicAction.ExecuteTarget(Target:TObject);
begin
end;

procedureTBasicAction.Notification(AComponent:TComponent;
Operation:TOperation);
begin
inheritedNotification(AComponent,Operation);
if(Operation=opRemove)and(AComponent=ActionComponent)then
FActionComponent:
=nil;
end;

procedureTBasicAction.UpdateTarget(Target:TObject);
begin
end;

functionTBasicAction.Execute:Boolean;
begin
ifAssigned(FOnExecute)then
begin
FOnExecute(Self);
Result:
=True;
end
elseResult:=False;
end;

functionTBasicAction.Update:Boolean;
begin
ifAssigned(FOnUpdate)then
begin
FOnUpdate(Self);
Result:
=True;
end
elseResult:=False;
end;

procedureTBasicAction.SetOnExecute(Value:TNotifyEvent);
var
I:Integer;
begin
if(TMethod(Value).Code<>TMethod(OnExecute).Code)or
(TMethod(Value).Data
<>TMethod(OnExecute).Data)then
begin
forI:=0toFClients.Count-1do
TBasicActionLink(FClients[I]).SetOnExecute(Value);
FOnExecute:
=Value;
Change;
end;
end;

procedureTBasicAction.Change;
begin
ifAssigned(FOnChange)thenFOnChange(Self);
end;

procedureTBasicAction.RegisterChanges(Value:TBasicActionLink);
begin
Value.FAction:
=Self;
FClients.Add(Value);
end;

procedureTBasicAction.UnRegisterChanges(Value:TBasicActionLink);
var
I:Integer;
begin
forI:=0toFClients.Count-1do
ifFClients[I]=Valuethen
begin
Value.FAction:
=nil;
FClients.Delete(I);
Break;
end;
end;

procedureTBasicAction.SetActionComponent(
constValue:TComponent);
begin
ifFActionComponent<>Valuethen
begin
ifAssigned(FActionComponent)then
FActionComponent.RemoveFreeNotification(Self);
FActionComponent:
=Value;
ifAssigned(FActionComponent)then
FActionComponent.FreeNotification(Self);
end;
end;

TBasicAction类中声明了三个关键的虚护方法以及一个关键的动态方法。

functionHandlesTarget(Target:TObject):Boolean;virtual;
procedureUpdateTarget(Target:TObject);
virtual;
procedureExecuteTarget(Target:TObject);
virtual;
functionExecute:Boolean;dynamic;

其中的动态方法Execute可以由TBasicActionLink类或是TBasicActionLink的派生类或是客户端程序代码调用,而该方法则会执行程序员在它的OnExecute事件中编写的事件处理程序。对于TBasicAction的派生类而言,例如处理Paste动作的TEditPase类,就可以改写HandlerTarget虚方法,并且在其中编写执行粘贴的程序代码。

TEditPaste=class(TEditAction)
public
procedureUpdateTarget(Target:TObject);
override;
procedureExecuteTarget(Target:TObject);
override;
end;
 
{ TEditPaste }
procedure TEditPaste.ExecuteTarget(Target: TObject);
begin
GetControl(Target).PasteFromClipboard;
end;
procedure TEditPaste.UpdateTarget(Target: TObject);
begin
Enabled := Clipboard.HasFormat(CF_TEXT);
end;

因此,当我们要使用Action设计模式时,可以编写TBasicAction的派生类,并且改写ExecuteTarget虚方法,就像上面提到的TEditPaste类一样。或是实现企业逻辑程序代码并且把它指定给TBasicAction类的OnExecute事件,然后再调用Execute虚方法。

我们通过继承TBasicAction类实现了请求对象类,那么如何将客户端与这些请求对象建立关联呢?这里就用到了TBasicActionLink。

TBasicActionLink=class(TObject)
private
FOnChange:TNotifyEvent;
protected
FAction:TBasicAction;
procedureAssignClient(AClient:TObject);
virtual;
procedureChange;
virtual;
functionIsOnExecuteLinked:Boolean;
virtual;
procedureSetAction(Value:TBasicAction);
virtual;
procedureSetOnExecute(Value:TNotifyEvent);
virtual;
public
constructorCreate(AClient:TObject);
virtual;
destructorDestroy;
override;
functionExecute(AComponent:TComponent
=nil):Boolean;virtual;
functionUpdate:Boolean;
virtual;
propertyAction:TBasicActionreadFActionwriteSetAction;
propertyOnChange:TNotifyEventreadFOnChangewriteFOnChange;
end;

...{TBasicActionLink}

constructorTBasicActionLink.Create(AClient:TObject);
begin
inheritedCreate;
AssignClient(AClient);
end;

procedureTBasicActionLink.AssignClient(AClient:TObject);
begin
end;

destructorTBasicActionLink.Destroy;
begin
ifFAction<>nilthenFAction.UnRegisterChanges(Self);
inheritedDestroy;
end;

procedureTBasicActionLink.Change;
begin
ifAssigned(OnChange)thenOnChange(FAction);
end;

functionTBasicActionLink.Execute(AComponent:TComponent):Boolean;
begin
FAction.ActionComponent:
=AComponent;
Result:
=FAction.Execute;
end;

procedureTBasicActionLink.SetAction(Value:TBasicAction);
begin
ifValue<>FActionthen
begin
ifFAction<>nilthenFAction.UnRegisterChanges(Self);
FAction:
=Value;
ifValue<>nilthenValue.RegisterChanges(Self);
end;
end;

functionTBasicActionLink.IsOnExecuteLinked:Boolean;
begin
Result:
=True;
end;

procedureTBasicActionLink.SetOnExecute(Value:TNotifyEvent);
begin
end;

functionTBasicActionLink.Update:Boolean;
begin
Result:
=FAction.Update;
end;

在上面的代码中我们可以看到TBasicActionLink的Execute方法实际上也就是调用了TBasicAction对象的虚方法Execute来负责响应客户端的请求。

应用举例

在通常的UI设计中,我们会在Form上放置一些菜单项,同时会把部分使用频率较高的功能以工具栏形式提供给用户。这些工具栏按钮实现的功能与菜单项完全相同,我们就可以使用Action模式来设计这些请求,然后将菜单项和工具栏按钮与这些Action对象对立关联即可。即使以后在用户界面上增加其它形式的调用,如上下文菜单,或是快捷键等,都可以直接与这些请求对象建立关联。可以很轻松地扩充用户发出请求的方式。

版权声明:本文为博主原创文章,未经博主允许不得转载。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics