使用命令模式重构播放器控制条

智慧并不产生于学历,而是来自对于知识的终生不懈的追求。这篇文章主要讲述使用命令模式重构播放器控制条相关的知识,希望能为你提供帮助。
1 命令模式的UML类图命令模式的UML类图如下图所示。

使用命令模式重构播放器控制条

文章图片

2 使用命令模式重构播放器控制条假如我们开发一个播放器,播放器有播放功能、拖动进度条功能、停止播放功能、暂停功能,我们在操作播放器的时候并不是直接调用播放器的方法,而是通过一个控制条去传达指令给播放器内核,具体传达什么指令,会被封装为一个个按钮。那么每个按钮就相当于对一条命令的封装。用控制条实现了用户发送指令与播放器内核接收指令的解耦。下面来看代码,首先创建播放器内核GPlayer类。
public class GPlayer {public void play(){ System.out.println("正常播放"); }public void speed(){ System.out.println("拖动进度条"); }public void stop(){ System.out.println("停止播放"); }public void pause(){ System.out.println("暂停播放"); }}

创建命令接口IAction类。
public interface IAction {void execute(); }

然后分别创建操作播放器可以接收的指令,播放指令PlayAction类的代码如下。
public class PlayAction implements IAction {private GPlayer gplayer; public PlayAction(GPlayer gplayer) { this.gplayer = gplayer; }public void execute() { gplayer.play(); }}

暂停指令PauseAction类的代码如下。
public class PauseAction implements IAction {private GPlayer gplayer; public PauseAction(GPlayer gplayer) { this.gplayer = gplayer; }public void execute() { gplayer.pause(); }}

拖动进度条指令SpeedAction类的代码如下。
public class SpeedAction implements IAction {private GPlayer gplayer; public SpeedAction(GPlayer gplayer) { this.gplayer = gplayer; }public void execute() { gplayer.speed(); }}

停止播放指令StopAction类的代码如下。
public class StopAction implements IAction {private GPlayer gplayer; public StopAction(GPlayer gplayer) { this.gplayer = gplayer; }public void execute() { gplayer.stop(); } }

【使用命令模式重构播放器控制条】最后创建控制条Controller类。
public class Controller { private List< IAction> actions = new ArrayList< IAction> (); public void addAction(IAction action){ actions.add(action); }public void execute(IAction action){ action.execute(); }public void executes(){ for(IAction action : actions){ action.execute(); } actions.clear(); } }

从上面代码来看,控制条可以执行单条命令,也可以批量执行多条命令。下面来看客户端测试代码。
public static void main(String[] args) {GPlayer player = new GPlayer(); Controller controller = new Controller(); controller.execute(new PlayAction(player)); controller.addAction(new PauseAction(player)); controller.addAction(new PlayAction(player)); controller.addAction(new StopAction(player)); controller.addAction(new SpeedAction(player)); controller.executes(); }

由于控制条已经与播放器内核解耦了,以后如果想扩展新命令,只需增加命令即可,控制条的结构无须改动。
3 命令模式在JDK源码中的应用首先来看JDK中的Runnable接口,Runnable相当于命令的抽象,只要是实现了Runnable接口的类都被认为是一个线程。
public interface Runnable { public abstract void run(); }

实际上调用线程的start()方法之后,就有资格去抢CPU资源,而不需要编写获得CPU资源的逻辑。而线程抢到CPU资源后,就会执行run()方法中的内容,用Runnable接口把用户请求和CPU执行进行解耦。
4 命令模式在JUnit源码中的应用再来看一个大家非常熟悉的junit.framework.Test接口。
package junit.framework; public interface Test { public abstract int countTestCases(); public abstract void run(TestResult result); }

Test接口中有两个方法,第一个是countTestCases()方法,用来统计当前需要执行的测试用例总数。第二个是run()方法,用来执行具体的测试逻辑,其参数TestResult是用来返回测试结果的。实际上,我们在平时编写测试用例的时候,只需要实现Test接口就被认为是一个测试用例,那么在执行的时候就会被自动识别。通常做法都是继承TestCase类,不妨来看一下TestCase的源码。
public abstract class TestCase extends Assert implements Test { ... public void run(TestResult result) { result.run(this); } ... }

实际上,TestCase类也实现了Test接口。我们继承TestCase类,相当于也实现了Test接口,自然就会被扫描成为一个测试用例。
关注微信公众号『 Tom弹架构 』回复“设计模式”可获取完整源码。

    推荐阅读