学习过设计模式的人都知道有一种行为模式叫做Command模式。在Delphi的VCL Framework中也使用到了这种模式,那就是Action模式。
命令模式使用的目的在于使用对象来封装客户端的请求命令,由于使用以对象封装,因此可以达到下面的效果:
- 请求对象可结合多态以及虚拟方法来提供更大的弹性;
- 负责执行请求的目的对象可以和客户端分离,这就表示多个客户端可以发生相同的请求对象,例如菜单或是工具栏按钮都可以发生打开文件的请求,如此一来菜单和工具栏按钮便可以使用相同的请求对象,而负责打开文件的程序代码并不会绑定到单一的菜单项或是工具栏按钮;
- 由于使用了请求对象,因此不单是图形用户界面可以触发请求,一般的程序代码也可以通过请求对象来执行特定的工作;
- 由于请求对象可以使用一个完整的类架构来实现,因此可以让客户端使用一致的程序代码格式来触发各种不同的请求。
实现
在Delphi的Classes单元中提供了Action设计模式的实现类和程序代码。
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类中声明了三个关键的虚护方法以及一个关键的动态方法。
procedureUpdateTarget(Target:TObject);virtual;
procedureExecuteTarget(Target:TObject);virtual;
functionExecute:Boolean;dynamic;
其中的动态方法Execute可以由TBasicActionLink类或是TBasicActionLink的派生类或是客户端程序代码调用,而该方法则会执行程序员在它的OnExecute事件中编写的事件处理程序。对于TBasicAction的派生类而言,例如处理Paste动作的TEditPase类,就可以改写HandlerTarget虚方法,并且在其中编写执行粘贴的程序代码。
public
procedureUpdateTarget(Target:TObject);override;
procedureExecuteTarget(Target:TObject);override;
end;
begin
GetControl(Target).PasteFromClipboard;
end;
begin
Enabled := Clipboard.HasFormat(CF_TEXT);
end;
因此,当我们要使用Action设计模式时,可以编写TBasicAction的派生类,并且改写ExecuteTarget虚方法,就像上面提到的TEditPaste类一样。或是实现企业逻辑程序代码并且把它指定给TBasicAction类的OnExecute事件,然后再调用Execute虚方法。
我们通过继承TBasicAction类实现了请求对象类,那么如何将客户端与这些请求对象建立关联呢?这里就用到了TBasicActionLink。
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对象对立关联即可。即使以后在用户界面上增加其它形式的调用,如上下文菜单,或是快捷键等,都可以直接与这些请求对象建立关联。可以很轻松地扩充用户发出请求的方式。
版权声明:本文为博主原创文章,未经博主允许不得转载。
相关推荐
在给出的文件信息中,我们可以了解到关于Delphi VCL(Visual Component Library,视觉组件库)的详细继承关系。VCL是Borland公司为Delphi开发的一套丰富的组件库,用于快速开发具有丰富图形用户界面的应用程序。 ...
安装 DevExpress for Delphi VCL 17.2.4 的过程非常简单,只需运行压缩包中的安装包,按照向导提示进行即可。"一键安装"意味着该版本已经集成了所有必要的组件和设置,用户无需进行复杂的配置,节省了开发者的宝贵...
在本压缩包中,开发者可以找到关于DevExpress Delphi VCL组件的各种技术细节、使用示例、API参考等,这些内容对于初学者和有经验的开发者来说都是非常宝贵的资源。 在Delphi的VCL框架中,开发者可以使用DevExpress...
在本主题中,我们关注的是如何在Delphi中利用VCL进行UDP通信。 标题"vcl.rar_Delphi VCL_delphi udp_vcl"暗示了我们将探讨如何在Delphi的VCL框架下实现基于UDP的网络通信。UDP(User Datagram Protocol)是一种无...
本教程将针对不熟悉DevExpress VCL安装过程的新手进行详细讲解,让新手能够顺利地在Delphi环境中安装并使用这一组件库。 首先,安装DevExpress VCL需要下载相应的安装包。在提供的文件列表中,“DevExpressVCL安装...
《Delphi VCL组件开发实例》是一份深入探讨Delphi集成开发环境中VCL(Visual Component Library)组件开发的专业文档。VCL是Delphi的核心部分,它提供了一整套丰富的用户界面控件和类库,使得开发者能够快速构建...
在Delphi 11.3开发环境中,开发者经常会遇到需要在一个传统的VCL(Visual Component Library)窗体上嵌入FireMonkey (FMX)组件的情况。这通常发生在开发跨平台应用程序时,因为FMX提供了对多操作系统的支持。本知识...
"神经网络 Delphi VCL"是一个专为Delphi设计的组件库,它允许开发人员在VCL(Visual Component Library)环境下轻松集成神经网络功能。 Delphi VCL是一个面向对象的库,用于创建Windows应用程序。它提供了丰富的...
Delphi VCL(Visual Component Library)架构是Delphi编程环境中核心的部分,它为开发者提供了丰富的图形用户界面(GUI)组件库。VCL是基于Object Pascal语言的,它使得开发高效、本地化的Windows应用程序变得非常...
在Delphi VCL(Visual Component Library)环境中,线程同步是一个关键的概念,特别是在多线程编程中。Synchronize方法是Delphi中用于在主线程和工作线程之间进行通信的关键工具,确保对用户界面(UI)的操作是安全...
通过Delphi VCL的强大可视化设计和事件驱动编程模式,可以极大地提高开发效率,同时保持代码的整洁和可维护性。 总的来说,"delphi VCL带源码,无限制经典mmtools,音频控件"是一个对于Delphi开发者特别是音频应用...
本文将深入探讨“NewNoteBook D6-XE7 Delphi VCL”这个NoteBook控件,它是专门为Delphi编程环境设计的。 首先,让我们了解“NewNoteBook”。标题中的“NewNoteBook D6-XE7”指的是该控件适用于Delphi从D6(Delphi 6...
在Delphi编程环境中,NativeExcel是一个强大的库,它允许开发者直接在VCL(Visual Component Library)框架下处理Excel文件,无需依赖Microsoft Office组件。这个库的出现极大地简化了Delphi程序员在处理Excel数据时...
本文将重点介绍标题为“delphi 蓝牙VCL——BlueToothFramework”的资源,通过深入解析其核心组件和功能,帮助读者理解如何在Delphi中构建蓝牙应用程序。 BlueToothFramework是专门为Delphi开发者设计的一个蓝牙VCL...
ZipTV VCL组件使得开发者无需深入了解压缩算法的细节,就能轻松地在Delphi程序中添加创建、读取、修改和提取ZIP档案的功能。 【标签】中的关键词: 1. **delphi_vcl**:指的是Delphi的Visual Component Library,它...
FFVCL则是基于FFmpeg的VCL(Visual Component Library)组件,将这些功能集成到Delphi的开发环境中。开发者可以像使用其他Delphi组件一样,通过拖放和设置属性来实现复杂的音视频操作。 在提供的压缩包中,包含以下...
DevExpress VCL for Delphi 是一套功能强大的可视化组件库,广泛应用于Delphi开发环境中的各种应用程序开发。该组件集提供了丰富的控件,包括数据网格、图表、报表等,可以极大提高开发效率,并使应用程序具有出色的...
在Delphi XE版本中,VCL源码可能不直接显示在默认安装的Source目录下,这可能是由于不同的安装序列号或特定的安装选项导致的。不过,通过特定的方法,如使用pj方法(可能指的是Project JEDI的工具或方法),用户可以...