使用命令模式重构播放器控制栏2 使用命令模式重构播放器控制栏如果我们开发一个播放器,播放器有播放、拖动进度条、停止播放、暂停等功能。我们在操作播放器的时候,并不是直接调用播放器的方法,而是通过一个控制条向播放器核心传达指令,具体传达的指令会封装成按钮。那么每个按钮就相当于封装了一个命令。控制条用于实现用户发送的指令与播放器内核接收的指令的解耦。我们看代码,首先创建播放器核心GPlayer类。publicclassGPlayer{publicvoidplay(){System.out.println("正常播放");}publicvoidspeed(){System.out.println("拖动进度条");}publicvoidstop(){System.out.println("停止播放");}publicvoidpause(){System.out.println("暂停播放");}}创建命令接口IAction类。公共接口IAction{voidexecute();}然后创建播放器可以接收的命令,播放命令PlayAction类的代码如下。公共类PlayAction实现IAction{privateGPlayergplayer;publicPlayAction(GPlayergplayer){this.gplayer=gplayer;}publicvoidexecute(){gplayer.play();}}PauseAction类的代码如下。公共类PauseAction实现IAction{privateGPlayergplayer;publicPauseAction(GPlayergplayer){this.gplayer=gplayer;}publicvoidexecute(){gplayer.pause();}}拖动进度条指令SpeedAction类的代码如下。公共类SpeedAction实现IAction{privateGPlayergplayer;publicSpeedAction(GPlayergplayer){this.gplayer=gplayer;}publicvoidexecute(){gplayer.speed();}}StopAction类的代码如下。公共类StopAction实现IAction{privateGPlayergplayer;publicStopAction(GPlayergplayer){this.gplayer=gplayer;}publicvoidexecute(){gplayer.stop();}}最后创建控件条Controller类。publicclassController{privateListactions=newArrayList();publicvoidaddAction(IActionaction){actions.add(action);}publicvoidexecute(IActionaction){action.execute();publicvoidexecutes(){for(IActionaction:actions){action.execute();}actions.clear();}}从上面的代码可以看出,控制条可以执行单个命令,也可以批量执行多个命令。我们来看客户端测试代码。publicstaticvoidmain(String[]args){GPlayerplayer=newGPlayer();控制器controller=newController();controller.execute(newPlayAction(player));controller.addAction(newPauseAction(player));.addAction(新的PlayAction(播放器));controller.addAction(newStopAction(player));controller.addAction(newSpeedAction(player));controller.executes();}由于控制条已经和播放器核心解耦了,以后如果要扩展新的命令,只需要添加命令即可,控制条的结构不需要改变.3 command模式在JDK源码中的应用首先看JDK中的Runnable接口。Runnable相当于命令的抽象。只要是实现了Runnable接口的类都被认为是一个线程。publicinterfaceRunnable{publicabstractvoidrun();}其实调用线程的start()方法后,就可以抢CPU资源了,不用写获取CPU资源的逻辑。线程抢到CPU资源后,会执行run()方法中的内容,使用Runnable接口将用户请求与CPU执行解耦。4 命令模式在JUnit源码中的应用我们来看一个大家非常熟悉的junit.framework.Test接口。包junit.framework;公共接口测试{publicabstractintcountTestCases();publicabstractvoidrun(TestResultresult);}Test接口中有两个方法,第一个是countTestCases()方法,用于统计当前执行的测试用例总数。第二个是run()方法,用于执行具体的测试逻辑,其参数TestResult用于返回测试结果。其实我们平时写测试用例的时候,只需要实现Test接口就可以认为是一个测试用例,执行的时候会被自动识别。通常的做法是继承TestCase类,那么我们来看一下TestCase的源码。publicabstractclassTestCaseextendsAssertimplementsTest{...publicvoidrun(TestResultresult){result.run(this);}...}其实TestCase类也实现了Test接口。我们继承了TestCase类,相当于实现了Test接口,自然会被扫描成一个测试用例。