命令模式(Command Pattren)属于行为型模式,它又被称做动作(Action)模式或事务(Transaction)模式。命令模式将请求者发送的请求封装为命令对象,这个命令对象将携带请求者的相关信息被传递到接收者,以此来达到请求者和接收者的解耦操作,让对象之间的调用更加灵活。在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适,所以需要使用命令模式。
命令模式(Command Pattren)的本质是对命令进行封装,它将发出命令的责任和执行命令的责任分割开,委派给不同的对象,此时发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。命令模式的核心在于引入了命令类,通过命令类来降低发送者和接收者的耦合度,请求发送者只需指定一个命令对象,再通过命令对象来调用请求接收者的处理方法。命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能
每一个命令都需要设计一个具体命令类,后期命令类过多可能影响性能
假设现在我要开发一个简单的文本框,文本框具有显示文本和撤销文本的功能。此时我需要先设计两个按钮类,分别为显示按钮**(ShowButton)和撤销按钮(RevokeButton),这两个类主要是做UI渲染方面的事情,而业务逻辑通过命令类(ShowCommand和RevokeCommand)传递到文本框类(TextBox)来执行。同时向文本框输入文本也写了一个输入器类(InputHandle)来模拟,输入器发送键入命令(InputCommand)**到文本框,文本框存储这些命令,为之后的撤销操作做准备。
package 设计模式.行为型模式.命令模式;
public interface Command {
boolean execute();
}
package 设计模式.行为型模式.命令模式;
import java.util.ArrayList;
public class TextBox {
private String content = ""; // 文本框中的文本
ArrayList<InputCommand> commandList = new ArrayList<>(); // 等待撤销的键入命令列表
/**
* 输入方法,获得待执行命令中的信息,将新的信息添加到当前文本中
* @param command 待执行的键入命令
*/
public void input(InputCommand command){
content += command.getText(); // 获取命令中的文本,添加到当前文本
command.clear(); // 清除命令中的文本,节省资源
commandList.add(command); // 将当前命令添加到键入命令列表,方便撤销操作
}
/**
* 撤销方法,为文本框提供撤销操作
*/
public void revoke(){
if (commandList.size() < 1) return; // 如果命令列表中没有命令则不执行
int index = commandList.size() - 1; // 获取最后一条命令的索引
InputCommand command = commandList.get(index); // 获取最后一条命令
content = content.substring(0,content.length()-command.getTextSize()); // 进行撤销操作
commandList.remove(index); // 删除最后一条键入命令
}
public void print(){
// 调用显示器显示文本
System.out.println(content);
}
}
package 设计模式.行为型模式.命令模式;
public class InputCommand implements Command {
private String text; // 待输入的文本
private TextBox textBox; //
private int textSize = -1;
InputCommand(TextBox textBox){
this.textBox = textBox;
}
public void setText(String text) {
this.text = text;
textSize = text.length(); // 获得文本长度
}
public String getText(){
return text;
}
public int getTextSize() {
return textSize;
}
/**
* 清除当前对象存储的键入文本信息,节省资源,由文本框调用
*/
public void clear(){
text = null;
}
@Override
public boolean execute() {
// 执行命令,如果文本存在则执行成功,否则执行失败
if (text != null) textBox.input(this);
else return false;
return true;
}
}
package 设计模式.行为型模式.命令模式;
public class ShowCommand implements Command {
TextBox textBox; // 在显示命令中维护接收者(文本框)
ShowCommand(TextBox textBox){
this.textBox = textBox;
}
@Override
public boolean execute() {
// 执行文本框的显示方法
if (textBox != null) textBox.print();
else return false;
return true;
}
}
package 设计模式.行为型模式.命令模式;
public class RevokeCommand implements Command {
private TextBox textBox; // 在撤销命令中维护接收者(文本框)
public RevokeCommand(TextBox textBox) {
this.textBox = textBox;
}
@Override
public boolean execute() {
// 执行调用者的撤销方法
if (textBox != null) textBox.revoke();
else return false;
return true;
}
}
package 设计模式.行为型模式.命令模式;
/**
* 模拟一个输入器
*/
public class InputHandle {
private TextBox textBox; // 指定一个文本框,用于键入文本
private String text = ""; // 模拟缓存区文本
public InputHandle(TextBox textBox){
this.textBox = textBox; // 维护一个文本框
}
public void setText(String text){ // 设置输入器的缓存文字
this.text += text;
}
/**
* 键入方法,将缓存区的文本通过命令写入到指定文本框中
*/
public void typing(){
// 将键入命令实体化,方便文本撤销操作
// 指定键入命令输出的文本框
InputCommand command = new InputCommand(textBox);
// 指定键入命令输入入的文字
command.setText(text);
// 如果该命令执行成功,清除缓存
if (command.execute()) text = "";
}
}
package 设计模式.行为型模式.命令模式;
public class ShowButton {
private Command command; // 维护一条显示命令
ShowButton(Command command){
this.command = command;
}
public void onClick(){
if (command != null) command.execute();
}
}
package 设计模式.行为型模式.命令模式;
/**
* 撤销按钮
*/
public class RevokeButton {
private TextBox textBox; // 维护一个文本框
public RevokeButton(TextBox textBox){
this.textBox = textBox;
}
public void onClick(){
// 点击撤销按钮时,新建一条撤销命令,并执行
new RevokeCommand(textBox).execute();
}
}
package 设计模式.行为型模式.命令模式;
public class CommandMain {
public static void main(String[] args) {
// 新建一个文本框
TextBox textBox = new TextBox();
// 新建一个输入器,用来模拟键盘输入
InputHandle inputHandle = new InputHandle(textBox);
// 新建一个显示按钮,在按钮中维护显示指令,在显示指令中维护一个文本框,以此达到点击按钮显示文本的操作
ShowButton showButton = new ShowButton(new ShowCommand(textBox));
// 新建一个撤销按钮,在撤销按钮中维护一个文本框
RevokeButton revokeButton = new RevokeButton(textBox);
//缓存文本“你好世界!”
inputHandle.setText("你好世界!");
// 通过键入命令键入到文本框
inputHandle.typing();
// 点击按钮,让文本框的内容显示在屏幕上
showButton.onClick();
// 再次键入文本
inputHandle.setText("hello,world!");
inputHandle.typing();
showButton.onClick();
//再次键入文本
inputHandle.setText("abc!");
inputHandle.typing();
showButton.onClick();
// 点击撤销按钮,在内部执行撤销命令
revokeButton.onClick();
// 显示撤销后的文本框文本信息
showButton.onClick();
revokeButton.onClick();
showButton.onClick();
}
}
你好世界!
你好世界!hello,world!
你好世界!hello,world!abc!
你好世界!hello,world!
你好世界!
Process finished with exit code 0