Command概述
UML概述
玩具代码案例1 - 模拟Restful框架的设计
手写一个简易的Web Controller MVC
命令注解
RestfulAnnotation
package online.javabook.gof.behavioral.patterns2.command2.restful.commands;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RestfulAnnotation {
String path();
HttpMethod httpMethod();
}
public enum HttpMethod {
GET,
POST,
PUT,
DELETE
}
命令的实现类
GroupController
package online.javabook.gof.behavioral.patterns2.command2.restful.controller;
import online.javabook.gof.behavioral.patterns2.command2.restful.commands.HttpMethod;
import online.javabook.gof.behavioral.patterns2.command2.restful.commands.RestfulAnnotation;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class GroupController {
@RestfulAnnotation(path = "/api/groups", httpMethod = HttpMethod.POST)
public void createUser(HttpServletRequest request, HttpServletResponse response) {
System.out.println("create group");
}
@RestfulAnnotation(path = "/api/groups", httpMethod = HttpMethod.GET)
public void readUser(HttpServletRequest request, HttpServletResponse response) {
System.out.println("read group");
}
@RestfulAnnotation(path = "/api/groups", httpMethod = HttpMethod.PUT)
public void updateUser(HttpServletRequest request, HttpServletResponse response) {
System.out.println("update group");
}
@RestfulAnnotation(path = "/api/groups", httpMethod = HttpMethod.DELETE)
public void deleteUser(HttpServletRequest request, HttpServletResponse response) {
System.out.println("delete group");
}
}
UserController
package online.javabook.gof.behavioral.patterns2.command2.restful.controller;
import online.javabook.gof.behavioral.patterns2.command2.restful.commands.HttpMethod;
import online.javabook.gof.behavioral.patterns2.command2.restful.commands.RestfulAnnotation;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class UserController {
@RestfulAnnotation(path = "/api/users", httpMethod = HttpMethod.POST)
public void createUser(HttpServletRequest request, HttpServletResponse response) {
System.out.println("create user");
}
@RestfulAnnotation(path = "/api/users", httpMethod = HttpMethod.GET)
public void readUser(HttpServletRequest request, HttpServletResponse response) {
System.out.println("read user");
}
@RestfulAnnotation(path = "/api/users", httpMethod = HttpMethod.PUT)
public void updateUser(HttpServletRequest request, HttpServletResponse response) {
System.out.println("update user");
}
@RestfulAnnotation(path = "/api/users", httpMethod = HttpMethod.DELETE)
public void deleteUser(HttpServletRequest request, HttpServletResponse response) {
System.out.println("delete user");
}
}
命令的注册器和执行器
RestfulRegister
package online.javabook.gof.behavioral.patterns2.command2.restful.register;
import online.javabook.gof.behavioral.patterns2.command2.restful.commands.HttpMethod;
import online.javabook.gof.behavioral.patterns2.command2.restful.commands.RestfulInstance;
import online.javabook.gof.behavioral.patterns2.command2.restful.commands.RestfulAnnotation;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class RestfulRegister {
private Map<String, RestfulInstance> restfulApiHashMap = new HashMap<>();
public void register(Class controllerClass) throws IllegalAccessException, InstantiationException {
Object controller = controllerClass.newInstance();
Method[] methods = controllerClass.getMethods();
for (Method method : methods) {
RestfulAnnotation annotation = method.getAnnotation(RestfulAnnotation.class);
if(annotation!= null) {
String restfulApiPath = annotation.path() + ":" + annotation.httpMethod();
RestfulInstance restfulApi = new RestfulInstance(controller, method);
restfulApiHashMap.put(restfulApiPath, restfulApi);
}
}
}
private RestfulInstance discover(String path, HttpMethod httpMethod) {
String restfulApiPath = path + ":" + httpMethod;
return restfulApiHashMap.get(restfulApiPath);
}
public void doRestful(String path, HttpMethod httpMethod, HttpServletRequest request, HttpServletResponse response) throws InvocationTargetException, IllegalAccessException {
discover(path, httpMethod).execute(request, response);
}
}
RestfulInstance
package online.javabook.gof.behavioral.patterns2.command2.restful.commands;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class RestfulInstance {
private Object controller;
private Method method;
public RestfulInstance(Object controller, Method method) {
this.controller = controller;
this.method = method;
}
public void execute(HttpServletRequest request, HttpServletResponse response) throws InvocationTargetException, IllegalAccessException {
method.invoke(controller, request, response);
}
}
命令执行者与命令
Main
package online.javabook.gof.behavioral.patterns2.command2.restful.app;
import online.javabook.gof.behavioral.patterns2.command2.restful.commands.HttpMethod;
import online.javabook.gof.behavioral.patterns2.command2.restful.controller.GroupController;
import online.javabook.gof.behavioral.patterns2.command2.restful.controller.UserController;
import online.javabook.gof.behavioral.patterns2.command2.restful.register.RestfulRegister;
import org.mockito.Mockito;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
public class Main {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, InvocationTargetException {
RestfulRegister restfulRegister = new RestfulRegister();
restfulRegister.register(UserController.class);
restfulRegister.register(GroupController.class);
HttpServletRequest mockedRequest = Mockito.mock(HttpServletRequest.class);
HttpServletResponse mockedResponse = Mockito.mock(HttpServletResponse.class);
restfulRegister.doRestful("/api/users", HttpMethod.POST, mockedRequest, mockedResponse);
restfulRegister.doRestful("/api/users", HttpMethod.GET, mockedRequest, mockedResponse);
restfulRegister.doRestful("/api/users", HttpMethod.PUT, mockedRequest, mockedResponse);
restfulRegister.doRestful("/api/users", HttpMethod.DELETE, mockedRequest, mockedResponse);
restfulRegister.doRestful("/api/groups", HttpMethod.POST, mockedRequest, mockedResponse);
restfulRegister.doRestful("/api/groups", HttpMethod.GET, mockedRequest, mockedResponse);
restfulRegister.doRestful("/api/groups", HttpMethod.PUT, mockedRequest, mockedResponse);
restfulRegister.doRestful("/api/groups", HttpMethod.DELETE, mockedRequest, mockedResponse);
}
}
Console
create user
read user
update user
delete user
create group
read group
update group
delete group
玩具代码案例2 - 模拟客户端编辑器的命令菜单
事实上你会发现GOF中的大多数设计模式都和客户端应用有着非常大的渊源,可能是设计模式提出的时候还是客户端应用的黄金时期。命令模式通常会在命令接口中提供可供操作的上下文数据,比如这个案例中的Editor。
命令接口
ICommand
package online.javabook.gof.behavioral.patterns2.command1.editor.commands;
import online.javabook.gof.behavioral.patterns2.command1.editor.context.Editor;
public interface ICommand {
void execute(Editor editor);
}
命令的实现类
CommandAnnotation
命令注解类型,我们在传统的命令模式中增加了注解来动态处理命令。设计模式之初Java应该还没有提供注解的支持。注解融入到设计模式之中也是非常方便的。
package online.javabook.gof.behavioral.patterns2.command1.editor.commands;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandAnnotation {
public String name();
}
CopyCommand
package online.javabook.gof.behavioral.patterns2.command1.editor.commands;
import online.javabook.gof.behavioral.patterns2.command1.editor.context.Editor;
@CommandAnnotation(name="copy")
public class CopyCommand implements ICommand {
@Override
public void execute(Editor editor) {
System.out.println("click copy button");
}
}
CutCommand
package online.javabook.gof.behavioral.patterns2.command1.editor.commands;
import online.javabook.gof.behavioral.patterns2.command1.editor.context.Editor;
@CommandAnnotation(name="cut")
public class CutCommand implements ICommand {
@Override
public void execute(Editor editor) {
System.out.println("click cut button");
}
}
NewCommand
package online.javabook.gof.behavioral.patterns2.command1.editor.commands;
import online.javabook.gof.behavioral.patterns2.command1.editor.context.Editor;
@CommandAnnotation(name="new")
public class NewCommand implements ICommand {
@Override
public void execute(Editor editor) {
System.out.println("click new button");
}
}
OpenCommand
package online.javabook.gof.behavioral.patterns2.command1.editor.commands;
import online.javabook.gof.behavioral.patterns2.command1.editor.context.Editor;
@CommandAnnotation(name="open")
public class OpenCommand implements ICommand {
@Override
public void execute(Editor editor) {
System.out.println("click open button");
}
}
PasteCommand
package online.javabook.gof.behavioral.patterns2.command1.editor.commands;
import online.javabook.gof.behavioral.patterns2.command1.editor.context.Editor;
@CommandAnnotation(name="paste")
public class PasteCommand implements ICommand {
@Override
public void execute(Editor editor) {
System.out.println("click paste button");
}
}
命令的执行器
Editor
这个案例中编辑器作为命令的容器,管理者和执行者。
package online.javabook.gof.behavioral.patterns2.command1.editor.context;
import online.javabook.gof.behavioral.patterns2.command1.editor.commands.CommandAnnotation;
import online.javabook.gof.behavioral.patterns2.command1.editor.commands.ICommand;
import java.util.HashMap;
import java.util.Map;
public class Editor {
private Map<String, ICommand> commandRegister = new HashMap<>();
public void registerCommand(Class<? extends ICommand> commandClass) throws IllegalAccessException, InstantiationException {
CommandAnnotation commandAnnotation = commandClass.getAnnotation(CommandAnnotation.class);
ICommand command = commandClass.newInstance();
commandRegister.put(commandAnnotation.name(), command);
}
public ICommand discoverCommand(String commandName) {
return commandRegister.get(commandName);
}
public void doCommand(String commandName) {
discoverCommand(commandName).execute(this);
}
}
命令执行者与命令
Main
package online.javabook.gof.behavioral.patterns2.command1.editor.app;
import online.javabook.gof.behavioral.patterns2.command1.editor.commands.*;
import online.javabook.gof.behavioral.patterns2.command1.editor.context.Editor;
public class Main {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Editor editor = new Editor();
editor.registerCommand(NewCommand.class);
editor.registerCommand(OpenCommand.class);
editor.registerCommand(CopyCommand.class);
editor.registerCommand(CutCommand.class);
editor.registerCommand(PasteCommand.class);
editor.doCommand("new");
editor.doCommand("open");
editor.doCommand("copy");
editor.doCommand("cut");
editor.doCommand("paste");
}
}
Console
click new button
click open button
click copy button
click cut button
click paste button