您现在的位置是:首页 > 正文

23种设计模式——命令模式

2024-02-01 01:08:21阅读 2

目录

命令模式

UML图

示例代码

使用场景

优点

实例——电脑开机

命令+备忘录模式


命令模式

本质:封装请求

命令模式又称为行动(Action)模式或交易(Transaction)模式。

命令模式:将一个请求封装为一个对象,对请求排队或记录请求日志,可以提供命令的撤销和恢复功能。

命令模式将发出操作的对象Invoker和实现操作的对象Receiver解耦。

UML图

共三级角色:发起人Ivoker、命令发出者Command、执行者Receiver。
Ivoker和Receive不直接交流,而是通过Command交流

将Receiver放到ConcreteCommand中,当请求到来(Invoker激活Command对象),ConcreteCommand将处理请求交给Receiver对象进行处理。
 

示例代码

public abstract class Command {
	protected Receiver receiver;

	public Command(Receiver receiver) {
		super();
		this.receiver = receiver;
	}
	
	public abstract void excute();

}
public class ConcreteCommand extends Command{

	public ConcreteCommand(Receiver receiver) {
		super(receiver);
	}

	@Override
	public void excute() {
		receiver.action();
	}

}
public class Invoker {
	private Command command;

	public void setCommand(Command command) {
		this.command = command;
	}
	
	public void excutecommand() {
		command.excute();
	}

}
public class Receiver{
	public void action() {
		System.out.println("执行请求");
	}
}
public class Main {

	public static void main(String[] args) {
		Receiver r=new Receiver();
		Command c=new ConcreteCommand(r);
		Invoker i=new Invoker();
		i.setCommand(c);
		i.excutecommand();
	}

}

使用场景

  • 请求队列化:把请求封装成为命令对象。
  • 取消操作:实现命令的撤销和重做
  • 把对系统的操作功能重新执行一遍:把这些操作功能的请求封装成命令对象,通过日志获取命令列表,从而重新执行一遍功能。
  • 需要事务的系统:如银行转账,买票。


优点

  • 容易设计一个命令队列。
  • 容易将命令记入日志。
  • 容易实现对请求的撤销和重做。
  • 容易增加新的具体命令类
  • 允许接收请求的一方决定是否要否决请求。
  • 把请求操作的对象和执行操作的对象分开。

实例——电脑开机

  • 发起人:机箱
  • 命令者:机箱上的按钮
  • 接收者:主板
//机箱:发起人
public class Box {
	private Command command;
	private String str;
	
	public void button() {
		command.execute(str);
	}

	public void setStr(String str) {
		this.str = str;
	}

	public void setCommand(Command command) {
		this.command = command;
	}
	
}
public interface Command {
	public void execute(String str);
}
//具体命令
public class ConcreteCommand implements Command{
	private MainBoardApi mainboard=null;
	
	public ConcreteCommand(MainBoardApi mainboard) {
		super();
		this.mainboard = mainboard;
	}


	@Override
	public void execute(String str) {
		this.mainboard.action(str);
	}
	
}
//把实现操作定义成接口,可以有不同的具体实现(但是我为了方便没有分成两个子类写)
public interface MainBoardApi {
	public void action(String str);
}

//实现操作
public class GigaMainBoard implements MainBoardApi{
	

	public GigaMainBoard() {
		super();
		// TODO Auto-generated constructor stub
	}

	@Override
	public void action(String str) {
		if(("open").equals(str)) {
			System.out.println("电脑打开");
		}else 
			System.out.println("电脑关闭");
	}
	
	
}
public class Main {

	public static void main(String[] args) {
		//实现操作的对象
		MainBoardApi mainboard=new GigaMainBoard();
		
		//命令列表
		ArrayList<Command> commands=new ArrayList<Command>();
		ConcreteCommand c1=new ConcreteCommand(mainboard);
		ConcreteCommand c2=new ConcreteCommand(mainboard);
		commands.add(c1);
		commands.add(c2);
		
		//发起人
		Box box=new Box();
		for(int i=0;i<commands.size();i++) {
			box.setStr((i%2==0)?"open":"close");
			box.setCommand(commands.get(i));
			box.button();
		}
	
	}

}

命令+备忘录模式

将命令模式和备忘录模式结合,实现计算器的撤销和重做。

public class Calculator {
	private double total=0;
	
	public void Operation(char op,int oper) {
		switch(op) {
		case '+':
			total+=oper;
			break;
		case '-':
			total-=oper;
			break;
		case '*':
			total*=oper;
			break;
		case '/':
			total/=oper;
			break;
		}
		System.out.println("total:"+total);
	}

}
public abstract class Command {
	public abstract void execute();
	public abstract void unexcute();

}
public class CalculatorCommand extends Command{
	char op;
	int oper;
	Calculator calculator;

	public CalculatorCommand(char op, int oper, Calculator calculator) {
		super();
		this.op = op;
		this.oper = oper;
		this.calculator = calculator;
	}

	public char getOp() {
		return op;
	}

	public void setOp(char op) {
		this.op = op;
	}


	public int getOper() {
		return oper;
	}

	public void setOper(int oper) {
		this.oper = oper;
	}


	public Calculator getCalculator() {
		return calculator;
	}

	public void setCalculator(Calculator calculator) {
		this.calculator = calculator;
	}


	@Override
	public void execute() {
		calculator.Operation(op, oper);
	}

	@Override
	public void unexcute() {
		calculator.Operation(Undo(op), oper);
	}
	
	private char Undo(char op) {
		char undo=' ';
		switch(op) {
		case '+':undo='-';
			break;
		case '-':undo='+';
			break;
		case '*':undo='/';
			break;
		case '/':undo='*';
			break;
		}
		return undo;
		
	}

}
public class User {
	private Calculator calculator=new Calculator();
	private ArrayList<Command> commands=new ArrayList<Command>();
	private int current;
	
	public void Redo(int levels) {
		System.out.println("redo "+levels+" level");
		for(int i=0;i<levels;i++) {
			System.out.println(commands.size()-1);
			if(current<commands.size()-1) {
				commands.get(current++).execute();
			}else {
				System.out.println("not redo");
			}
		}
	}
	
	public void Undo(int levels) {
		System.out.println("undo "+levels+" level");
		for(int i=0;i<levels;i++) {
			if(current>0)
				commands.get(--current).unexcute();
			else
				System.out.println("not undo");
		}
	}
	
	public void Compute(char op,int oper) {
		Command command =new CalculatorCommand(op,oper,calculator);
		command.execute();
		commands.add(command);
		current++;
	}
	
}
public class Main {

	public static void main(String[] args) {
		User user=new User();
		user.Compute('+',100);
		user.Compute('-',50);
		user.Compute('*',10);
		user.Compute('/',2);
		user.Undo(4);//撤销4次
		user.Redo(3);//重做3次
	}

}

网站文章

  • SpringSecurity(前后端分离版)[3]-授权

    SpringSecurity(前后端分离版)[3]-授权

    例如一个学校图书馆的管理系统,如果是普通学生登录就能看到借书还书相关的功能,不可能让他看到并且去使用添加书籍信息,删除书籍信息等功能。SpringSecurity为我们提供了基于注解的权限控制方案,这...

    2024-02-01 01:08:13
  • log4j2漏洞检测和利用

    log4j2漏洞检测和利用

    漏洞检测使用的是BP插件,插件地址。JNDI注入工具,工具地址 https://github.com/welk1n/JNDI-Injection-Exploit/releases/tag/v1.0,命令如下:将以下命令进行base64编码,IP替换为你攻击机IP。使用工具命令如下:burp发包:反弹shell成功:

    2024-02-01 01:08:06
  • 更改MAC终端显示的主机名

      其实也简单。 之前显示 wuxi:~ tsit$ 执行命令 sudo scutil --set HostName taishan 关闭当前终端,另起一个终端 taishan:~ tsit$

    2024-02-01 01:07:39
  • 百度地图的使用---1、标注(Marker)的使用以及自定义样式 最新发布

    百度地图的使用---1、标注(Marker)的使用以及自定义样式 最新发布

    使用百度地图Marker标记,更改图标样式

    2024-02-01 01:07:22
  • MCU常见通信协议 UART /SPI / I2C 学习记录

    MCU常见通信协议 UART /SPI / I2C 学习记录

    MCU 常见通信协议详解

    2024-02-01 01:07:16
  • mysql查看分片键

    查看表分片:UDAL show config tablerule where tablename in ('表名')

    2024-02-01 01:06:33
  • Redis的5大数据类型

    Redis的5大数据类型

    Redis的5大数据类型

    2024-02-01 01:06:26
  • java -jar .jar -c_如何从jar文件创建C库? - java

    我有一个图书馆的jar文件,其中的内容是一堆.class文件spl├── acm│ ├── graphics│ │ ├── DrawLineElement.class│ │ ├── EndRegionElement.class│ │ ├── FinalPathElement.class│ │ ├── G3DRect.class│ │ ├── GArc.c...

    2024-02-01 01:06:19
  • PLSQL类型相关操作

    1.写一个PLSQL程序,输出”hello world”字符串,语法:dbms_output.put_line('需要输出的字符串');begin --向SQLPLUS客户端工具输出字符串 dbms_output.put_line('hello 你好');end;注意: dbms_output是oracle中的一个输出对象 put_line是上述对象的一个方法,用于输出一个字

    2024-02-01 01:05:52
  • 《中软笔记》仿京东图片浏览

    《中软笔记》仿京东图片浏览

    本片文章的内容为仿京东商品图片浏览时放大的效果如图所示:效果分析:当鼠标移上左边时候该图片就会被放大,并且在右边显示;移动的时候还可以查看该物品的其他部位;鼠标移除就会被隐藏起来,不占物理空间。解决思路:1.写样式不管啥情况先写出来看看再去搞功能右边一个div,放入图片设置图片宽高,左边一个设置为右边div图片的 两倍大;2.写事件分析可知有三种事件(通过触发小盒子的事件,...

    2024-02-01 01:05:43