命令模式Command Pattern[共12页]_第1页
命令模式Command Pattern[共12页]_第2页
命令模式Command Pattern[共12页]_第3页
命令模式Command Pattern[共12页]_第4页
命令模式Command Pattern[共12页]_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、描述:通常,面向对象应用程序是由一组能够提供有限的、专注于功能的相互交互的对象集合组成。为了响应用户的交互动作,应用程序执行一系列的处理。为了响应用户的请求,应用程序使用不同的对象提供的服务处理请求。根据实现,应用可以指定一个对象,这个指定的对象可以调用不同对象上的操作,被称为调用者(invoker)。(译者注:其实个人认为这个invoker在这里主动地成分更大,它是偏向于调用其他对象,这个区别就像英语employ这个动词是雇佣的意思,employee是员工?被雇佣的对象,而employer是雇主?雇佣的主动者,那么在这里的invoker是一个道理)。调用者(invoker)可以看作为客户应用

2、程序的一部分。那些包含提供处理请求服务实现的对象集合成为接受对象(ReceiverObject)。Figure30.1:ObjectInteraction?BeforeApplyingtheCommandPattern在这种设计中,发出请求的应用程序和提供处理请求服务的接受对象(ReceiverObject)集合之间彼此是紧密关联的,因为它们之间直接相互交互。这导致了在调用者(invoker)实现中会包含大量的if条件语句。 1. 2. if(RequestType=TypeA) 3. /dosomething 4. 5.6. if(RequestType=TypeB) 7. /dosomet

3、hing 8. 9. 当一种新的处理类型需要加入的应用时,现存的代码需要进行修改?这违背了面向对象开放?关闭的基本原则。1. 2. if(RequestType=TypeA) 3. /dosomething 4. 5. 6. if(RequestType=NewType) 7. /dosomething 8. 9. 使用命令模式,代表客户发布请求的调用者(invoker)和服务的处理者?接受对象(ReceiverObject)之间不具有耦合性。命令模式推荐创建一个可以为响应客户请求而执行处理或者采取动作的抽象。指定这个抽象声明一个被其它不同的具体的实现者所实现的共同接口,这些具体的实现者称之为

4、命令对象(CommandObjects)。每一个命令对象(CommandObject)代表一种不同的客户请求和对其进行的相应处理。在图30.2中,command接口代表了这个抽象。它声明一个excute方法,它由两个具体的实现者(类)?ConcreteCommand_1和ConcreteCommand_2。Figure30.2:CommandObjectHierarchy一个给定的命令对象(commandObject)负责提供处理它所代表的请求的功能,但是命令对象并不包含此功能的真实实现,它是通过使用接受对象(ReceiverObject)来提供处理功能。(如图30.3)Figure30.3:

5、ClassAssociation?AftertheCommandPatternIsApplied当客户应用程序响应用户(或者其他应用)的交互而需要提供服务时:(1)客户创建需要的接受对象(ReceiverObject)。(2)客户创建一个相应的命令对象(CommandObject),并用在步骤1中创建的接受对象(ReceiverObject)配置这个命令对象。(3)客户创建一个调用者的实例(invoker),并用在步骤2中创建的命令对象(CommandObject)配置调用者。(4)调用者调用命令对象(CommandObject)上的execute方法。(5)作为execute方法实现的一部分

6、,特定的命令对象(CommandObject)调用它所包含的接受对象上的必要方法来提供需要的服务。在新的设计中:(1)客户/调用者(invoker)不直接与接受对象(Receiver)进行交互,它们之间完全不耦合。(2)当应用程序需要提供新的类型的时候,可以增加一个新的命令(Command)对象。这不需要修改调用者(invoker)的代码。因此新的设计保证了面向对象的开放?封闭的原则。(3)因为一个请求被指定为对象的形式,那么就存在以下可能性:1)把命令对象保存到持久介质上。以后进行执行。应用反向处理,实现恢复特性。2)把不同的命令对象分组成一个独立的单元。以下是一个FTP(FileTrans

7、ferProtocol)客户事例应用程序,对于在实际应用程序中如何应用命令模式提供了很好的参考。 例子1:让我们建立一个应用程序来模拟FTP客户端的工作。在Java中,简单的FTP客户用户接口可以使用如下组件设计。(1)两个JList对象用于本地和远程文件系统的显示。(2)四个JButton对象用于初始不同的请求类型:上传、下载、删除和退出。用户接口组件摆列在一个frame中,如图30.4Figure30.4:SimpleFTPClientUIDisplay每一个JButton对象创建的时候,实现了ActionListener接口的Button-Handler类的一个事例是一个ActionLi

8、stener的集合。1. publicclassFTPGUIextendsJFrame 2. 3. 4. /Createbuttons 5. btnUpload=newJButton(FTPGUI.UPLOAD); 6. btnUpload.setMnemonic(KeyEvent.VK_U); 7. 8. 9. ButtonHandlervf=newButtonHandler(); 10. btnUpload.addActionListener(vf); 11. btnDownload.addActionListener(vf); 12. btnDelete.addActionListene

9、r(vf); 13. btnExit.addActionListener(vf); 14. 15. 16. /endofclass 因为这个相同的ButtonHandler实例是所有JButton对象的Action-Listener的一个集合,actionPerformed方法被所有的JButton对象调用。因此,ButtonHandler对象必须检测哪一个按钮被按下,并执行相应的处理。从Listing30.1中可以看到,actionPerformed方法的代码因为条件语句很不规则。当有很多按钮和菜单对象需要添加到FTP用户界面时,actionPerformed方法的代码就很混乱。同时,一个新

10、的按钮对象被添加时,现在的actionPerformed方法的代码必须修改。这违反了面向对象的开放?关闭原则。Listing30.1:ButtonHandlerClass1. classButtonHandlerimplementsActionListener 2. publicvoidactionPerformed(ActionEvente) 3. /ifstatements-fordifferenttypesofclientrequests 4. if(e.getActionCommand().equals(FTPGUI.EXIT) 5. System.exit(1); 6. 7. if(

11、e.getActionCommand().equals(FTPGUI.UPLOAD) 8. intindex=localList.getSelectedIndex(); 9. StringselectedItem= 10. localList.getSelectedValue().toString(); 11. (DefaultListModel)localList.getModel().remove( 12. index); 13. (DefaultListModel)remoteList.getModel(). 14. addElement(selectedItem); 15. 16. i

12、f(e.getActionCommand().equals(FTPGUI.DOWNLOAD) 17. intindex=remoteList.getSelectedIndex(); 18. StringselectedItem= 19. remoteList.getSelectedValue().toString(); 20. (DefaultListModel)remoteList.getModel().remove( 21. index); 22. (DefaultListModel)localList.getModel(). 23. addElement(selectedItem); 2

13、4. 25. if(e.getActionCommand().equals(FTPGUI.DELETE) 26. intindex=localList.getSelectedIndex(); 27. if(index=0) 28. (DefaultListModel)localList.getModel(). 29. remove(index); 30. 31. index=remoteList.getSelectedIndex(); 32. if(index=0) 33. (DefaultListModel)remoteList.getModel(). 34. remove(index);

14、35. 36. 37. 38. 让我们使用命令模式重新设计这个应用。应用命令模式,我们把不同按钮对象相关联的功能抽象一个Command-face接口。1. interfaceCommandInterface 2. publicvoidprocessEvent(); 3. 不同的按钮对象可以实现这个接口,独自成为自己的命令对象。但是,这是不推荐的,因为:(1)JButton类是一个高复用的类,在用JavaSwing库创建应用用户界面的许多场合,JButton类都被使用。实现特定的CommandInterface接口可能不是适用于所有的情况。(2)如果JButton类实现了CommandInter

15、face接口,它需要实现处理在用户界面(接口)上不同的JButton对象所对应的诸如上传、下载等不同请求的功能。这会增加不相关的功能到JButton类中?导致低聚和。另外:1)这会导致不规则的条件语句。2)每增加一个新的按钮到用户界面上(接口),它都需要改变现在的processEvent方法的实现。这违背了面向对象的开放?关闭的原则。为了解决这些问题,对应不同请求类型的按钮类被设计为JButton类的子类(Listing30.2)。这些子类实现CommandInterface接口。作为processEvent方法实现的一部分,JButton类的每一个子类提供处理它所代表的不同请求的功能。Lis

16、ting30.2:JButtonSubclassestoPerformDifferentFTPOperations1. classUploadButtonextendsJButton 2. implementsCommandInterface 3. publicvoidprocessEvent() 4. intindex=localList.getSelectedIndex(); 5. StringselectedItem= 6. localList.getSelectedValue().toString(); 7. (DefaultListModel)localList.getModel()

17、.remove( 8. index); 9. (DefaultListModel)remoteList.getModel().addElement( 10. selectedItem); 11. 12. publicUploadButton(Stringname) 13. super(name); 14. 15. 16. classDownloadButtonextendsJButton 17. implementsCommandInterface 18. publicvoidprocessEvent() 19. intindex=remoteList.getSelectedIndex();

18、20. StringselectedItem= 21. remoteList.getSelectedValue().toString(); 22. (DefaultListModel)remoteList.getModel().remove( 23. index); 24. (DefaultListModel)localList.getModel().addElement( 25. selectedItem); 26. 27. publicDownloadButton(Stringname) 28. super(name); 29. 30. 31. classDeleteButtonexten

19、dsJButton 32. implementsCommandInterface 33. publicvoidprocessEvent() 34. intindex=localList.getSelectedIndex(); 35. if(index=0) 36. (DefaultListModel)localList.getModel().remove( 37. index); 38. 39. index=remoteList.getSelectedIndex(); 40. if(index=0) 41. (DefaultListModel)remoteList.getModel().rem

20、ove( 42. index); 43. 44. 45. publicDeleteButton(Stringname) 46. super(name); 47. 48. 49. classExitButtonextendsJButton 50. implementsCommandInterface 51. publicvoidprocessEvent() 52. System.exit(1); 53. 54. publicExitButton(Stringname) 55. super(name); 56. 57. 58. Figure30.5:FTPUI?CommandObjectHiera

21、rchyFTP用户界面可以使用这些新的JButton的子类来构成。应用程序其他部分保持不变,actionPerformed方法非常简单,只有两行代码。1. classbuttonHandlerimplementsActionListener 2. publicvoidactionPerformed(ActionEvente) 3. CommandInterfaceCommandObj= 4. (CommandInterface)e.getSource(); 5. CommandOcessEvent(); 6. 7. 在新的设计中,不管是增加新的按钮还是菜单项,需要创建一个实现了Co

22、mmandInterface接口新的命令对象(CommandObject)。一个新的命令对象可以在不需要修改现在的actionPerformed方法的情况下,无缝的添加到应用中。这种设计的负面影响是导致了大量的类。例子2:让我们建立一个在图书馆中管理项目数据库中项目的应用程序。特定的图书馆包括如下项目:书、CD、video和DVD。这些项目被分成类别,一个给定项目可以属于一个或者多个类别。例如,一个新的电影video可以同时属于video类别和新发布(NewReleases)类别。让我们定义两个类?Item和Category?(Listing30.3)分别代表数据库中特定的条目和条目的分类。L

23、isting30.3:ItemandCategoryClasses1. publicclassItem 2. privateHashMapcategories; 3. privateStringdesc; 4. publicItem(Strings) 5. desc=s; 6. categories=newHashMap(); 7. 8. publicStringgetDesc() 9. returndesc; 10. 11. publicvoidadd(Categorycat) 12. categories.put(cat.getDesc(),cat); 13. 14. publicvoid

24、delete(Categorycat) 15. categories.remove(cat.getDesc(); 16. 17. 18. publicclassCategory 19. privateHashMapitems; 20. privateStringdesc; 21. publicCategory(Strings) 22. desc=s; 23. items=newHashMap(); 24. 25. publicStringgetDesc() 26. returndesc; 27. 28. publicvoidadd(Itemi) 29. items.put(i.getDesc(

25、),i); 30. System.out.println(Item+i.getDesc()+ 31. hasbeenaddedtothe+ 32. getDesc()+Category); 33. 34. publicvoiddelete(Itemi) 35. items.remove(i.getDesc(); 36. System.out.println(Item+i.getDesc()+ 37. hasbeendeletedfromthe+ 38. getDesc()+Category); 39. 40. Figure30.6:Item-CategoryAssociation从Item和C

26、ategory类的设计和实现可以看到,Category对象维护了当前成员项目的一个列表。同样,一个Item对象也维护了一个它所归属的类别的类表。为了简单,让我们假定图书馆项目管理应用仅处理增加和删除项目。应用命令模式,处理增加和删除项目请求的动作可以设计为共同接口CommandInterface的实现。CommandInterface提供一个处理增加和删除项目请求的抽象。CommandInterface实现者?AddCommand和DeleteCommand?在图30.7中分别代表了增加和删除项目的请求。Figure30.7:CommandObjectHierarchyLetusfurther

27、defineaninvokerItemManagerclass.1. publicclassItemManager 2. CommandInterfacecommand; 3. publicvoidsetCommand(CommandInterfacec) 4. command=c; 5. 6. publicvoidprocess() 7. command.execute(); 8. ItemManager类:(1)包含Command对象(2)调用Command对象的execute方法,作为自己process方法实现的一部分。(3)提供setCommand方法允许客户对象配置Command对象

28、客户CommandTest使用调用者(invoker)ItemManager得到增加和删除项目请求的处理。应用程序流程:增加和删除一个项目,客户CommandTest(Listing30.4)(1)创建必须的Item和Category对象,这些对象扮演接受(Receiver)对象的角色。(2)创建一个对应现在请求的适当的命令(Command)对象,把步骤1中创建的接受(Receiver)对象在命令(Command)对象创建时传递给它。(3)创建一个ItemManager类的一个实例,用在步骤2中创建的命令(Command)对象配置它。(4)调用ItemManager上的process()方法,

29、ItemManager调用命令(Command)对象上的execute方法。命令(Command)对象翻过来调用需要的接受(Receiver)对象上的方法。不同的Item和Category接受(Receiver)对象执行真正的请求处理。为了保持例子的简单,在实现中没有数据库访问逻辑的实现。Item和Category对象的实现只是简单的现实信息。Listing30.4:ClientCommandTestClass1. publicclassCommandTest 2. publicstaticvoidmain(Stringargs) 3. /AddanitemtotheCDcategory 4. /createReceiverobjects 5. ItemCD=newItem(ABeautifulMind); 6. CategorycatCD=newCategory(CD); 7. /createthecommandobject 8. CommandInterfacecommand=newAddCommand(CD,catCD); 9. /createtheinvoker 10. ItemM

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论