读书人

下令(command)模式

发布时间: 2012-11-15 15:16:14 作者: rapoo

命令(command)模式

命令模式是对命令的封装,把发出命令的责任与执行命令的责任分割开,委派给不对的对象。其优点就是解耦了发送者和接受者之间联系。 发送者调用一个操作,接受者接受请求执行相应的动作,因为使用Command模式解耦,发送者无需知道接受者任何接口。类似于c语言里的回调函数。

在c语言中的回调函数的使用: 若为几个不同的设备分别写了不同的显示函数:void showInTV(); void showInComputer(); void showInNotebook()...等等。这是我们想用一个统一的显示函数,此时就可以用回掉函数--void show(void (*ptr)()); 使用时根据所传入的参数不同而调用不同的回调函数。

#include <stdio.h>void showInTV() //在电视设备的显示 {printf("display in TV\n");}void showInComputer() //在电脑设备上的显示{printf("display in computer\n");}void showInNotebook() //在笔记本上的显示{printf("display in notebook\n");}void show(void (*ptr)()) //定义回调函数{(*ptr)();}int main() {show(showInTV); //相当于调用showInTV()printf("********************\n");show(showInComputer); //相当于调用showInComputer()printf("********************\n");show(showInNotebook); //相当于调用showInNotebook()return 0;}

?java虽然不支持指针,但通过命令模式可以达到同样的目的。

命令模式的类图:

?下令(command)模式

典型的Command模式需要有一个接口.接口中有一个统一的方法,这就是"将命令/请求封装为对象":

/** * 命令角色:声明了一个给所有具体命令类的抽象接口, * 也可以使用抽象类实现 */public interface  ShowCommand {public void show();}

?具体不同命令/请求代码是实现接口Command,下面有三个具体命令

/** *具体命令:在TV设备中显示命令  */public class ShowInTVCommand implements ShowCommand {@Overridepublic void show() {System.out.println("display in TV");}}/** *具体命令:在Computer设备中显示命令  */public class ShowInComputerCommand implements ShowCommand {@Overridepublic void show() {System.out.println("display in Computer");}}/** *具体命令:在notebook设备中显示命令  */public class ShowInNotebookCommand implements ShowCommand {@Overridepublic void show() {System.out.println("display in notebook");}}

?按照通常做法,我们就可以直接调用这三个Command,但是使用Command模式,我们要将他们封装起来,扔到黑盒子List里去:

/** * 负责组织模块和命令 * */public class ShowFunction {private static Map<String, ShowCommand> map = new HashMap<String, ShowCommand>();static { //将每一个模块和命令名称映射起来map.put("TV", new ShowInTVCommand());map.put("computer", new ShowInComputerCommand());map.put("notebook", new ShowInNotebookCommand());}public static ShowCommand getCommand(String key) {return map.get(key);}}

??客户端调用命令时,无需关心来源,只需关心调用?

public class Client {public static void main(String[] args)  {                 //调用在TV设备中显示ShowCommand showInTV = ShowFunction.getCommand("TV");showInTV.show();}}?

由此可见,调用者基本只和接口打交道,不和具体实现交互,这也体现了一个原则,面向接口编程,这样,以后增加第四个具体命令时,就不必修改调用者Client中的代码了.

command模式的缺点:会导致某些系统有过多的具体命令类,这会使命令模式在某些系统中变得不实际。

解决方法1:

利用java的反射机制:

将具体的命令类都用方法代替,即将所有的命令都封装到一个接口中:

public interface  ShowCommand {public void ShowInTVCommand();public void ShowInComputerCommand();public void ShowInNotebookCommand();}

?具体命令类

public class DefaultShowCommand implements ShowCommand {@Overridepublic void ShowInComputerCommand() {System.out.println("display in computer");}@Overridepublic void ShowInNotebookCommand() {System.out.println("display in notebook");}@Overridepublic void ShowInTVCommand() {System.out.println("display in TV");}}

负责组织模块和命令的接口

public interface CommandLoader {public void execute(String device, Object[] args);}

?实现此接口

public class DefaultCommandLoader implements CommandLoader {private ShowCommand command;private Map<String, Method> methods = new HashMap<String, Method>();public DefaultCommandLoader(ShowCommand command) {this.command = command;init();}private void init() {Method[] m = command.getClass().getMethods();for (Method method : m) {if (method.getName().indexOf("TV") != -1) {methods.put("TV", method);} else if (method.getName().indexOf("Computer") != -1) {methods.put("computer", method);} else if (method.getName().indexOf("Notebook") != -1) {methods.put("notebook", method);}}}@Overridepublic void execute(String device, Object[] args) {Method me = methods.get(device);if (me == null) {throw new NullPointerException("not found command");} try {me.invoke(command, args);} catch (Exception e) {throw new RuntimeException("Load command[" + me.getName() + "error");}}}

?客户端

public class Client {public static void main(String[] args) {CommandLoader loader = new DefaultCommandLoader(new DefaultShowCommand());loader.execute("TV", null);}}

?这种方法利用反射机制实现的减少具体命令类,但缺点是明显的:1,性能降低,2,不符合开闭原则

?

解决方法2

利用静态内部类

这里只给一些提示,具体代码以后抽时间补上

?

public class Command {public static class ShowInComputerCommand implements ShowCommand {@Overridepublic void show() {System.out.println("display in Computer");}}public static class ShowInTVCommand implements ShowCommand {@Overridepublic void show() {System.out.println("display in TV");}}public static class ShowInNotebookCommand implements ShowCommand {@Overridepublic void show() {System.out.println("display in notebook");}}

注:上传的文件command_01.rar是上面command模式实现的例子,command_02.rar是利用反射实现的command例子。

读书人网 >软件架构设计

热点推荐