JAVA设计模式——命令模式

本文介绍命令模式的基本概念,包括如何将请求封装成对象,利用不同请求、队列或日志参数化其他对象,以及如何支持可撤销操作。文章还提供了一个具体的例子,展示了如何通过命令模式控制灯光开关。

        命令模式

将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

我们知道一个命令各对象通过在特定接收者上绑定一组动作来封装一个请求。要达到这一点,命令对象将动作和接收者包进对象中。这个对象只暴露出一个execute()方法,当此方法被调用时,接收者就会进行这些动作。从外面来看,其他对象不知道究竟哪个接收者进行了哪些动作,只知道如果调用execute()方法,请求的目的就能达到。

         具体例子

所有命令对象实现相同的接口:Command.java

package com.designpattern.command;

public interface Command {
	public void execute();
	public void undo();
	
}


Light.java

package com.designpattern.command;

public class Light {
	private boolean on = false;

	public void on() {
		this.on = true;
	}

	public void off() {
		this.on = false;
	}

	public String getStatus() {
		if (on) {
			return "ON";
		} else {
			return "OFF";
		}
	}
}

开灯的命令 对象:OnCommand.java,定义了动作和接收者之间的绑定关系。调用者只要调用execute()方法就可以发出请求,然后调用接收者的一个或多个动作。

package com.designpattern.command;

public class OnCommand implements Command {
	private Light light;

	public OnCommand(Light l) {
		this.light = l;
	}

	@Override
	public void execute() {
		light.on();
	}

	@Override
	public void undo() {
		light.off();
		System.out.println("The light is off!");
	}

}
关灯的命令对象:OffCommand.java

package com.designpattern.command;

public class OffCommand implements Command {

	private Light light;
	
	public OffCommand(Light l){
		this.light = l;
	}
	
	@Override
	public void execute() {
		light.off();
	}

	@Override
	public void undo() {
		light.on();
		System.out.println("The light is on!");
	}

}

空命令:NoCommand.java,将处理null的责任转移给空命令对象,当调用它的execute()方法时,这个对象什么事情都不做。

package com.designpattern.command;

public class NoCommand implements Command {

	@Override
	public void execute() {
		// TODO Auto-generated method stub

	}

	@Override
	public void undo() {
		// TODO Auto-generated method stub

	}

}

调用者:Invoker.java,持有一个命令对象,并在某个时间点调用命令对象的execute()方法,将请求付诸实行。

package com.designpattern.command;

//调用者
public class Invoker {

	private Command command;

	private Command undoCommand;

	public Invoker() {
		command = new NoCommand();
		undoCommand = new NoCommand();
	}

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

	public void pressButton() {
		this.command.execute();
		undoCommand = command;
	}

	public void undoPress() {
		undoCommand.undo();
	}
}

测试类:Test.java,负责创建一个具体的命令,并设置其接收者。

package com.designpattern.command;

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		Light light = new Light();
		
		Command on = new OnCommand(light);//具体命令,light为接收者
		Command off = new OffCommand(light);
		
		Invoker invoker = new Invoker();
		invoker.setCommand(on);
		invoker.pressButton();
		invoker.undoPress();
		
		System.out.println("Light  "+light.getStatus());
	}

}

          要点总结

1、命令模式将发出请求的对象和执行请求的对象解耦。

2、在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接收者和一个或一组动作。

3、调用者通过调用命令对象的execute()方法发出请求,这会使得接收者的动作被调用。

4、调用者可以接收命令当做参数,甚至在运行时动态地进行。

5、命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行前的状态。

6、宏命令是命令的一种简单的延伸,允许调用多个命令。宏方法也可以支持撤销。

7、实际操作时,很常见使用“聪明”命令对象,也就是直接实现了请求,而不是将工作委托给接收者。

8、命令也可以用来实现日志和事务系统。


目录: 前 言 第一部分 大旗不挥,谁敢冲锋——热身篇 第1章 单一职责原则 1.1 我是“牛”类,我可以担任多职吗 1.2 绝杀技,打破你的传统思维 1.3 我单纯,所以我快乐 1.4 最佳实践 第2章 里氏替换原则 2.1 爱恨纠葛的父子关系 2.2 纠纷不断,规则压制 2.3 最佳实践 第3章 依赖倒置原则 3.1 依赖倒置原则的定义 3.2 言而无信,你太需要契约 3.3 依赖的三种写法 3.4 最佳实践 第4章 接口隔离原则 4.1 接口隔离原则的定义 4.2 美女何其多,观点各不同 4.3 保证接口的纯洁性 4.4 最佳实践 第5章 迪米特法则 5.1 迪米特法则的定义 5.2 我的知识你知道得越少越好 5.3 最佳实践 第6章 开闭原则 6.1 开闭原则的定义 6.2 开闭原则的庐山真面目 6.3 为什么要采用开闭原则 6.4 如何使用开闭原则 6.5 最佳实践 第二部分 我惹了谁——真刀实枪篇 第7章 单例模式 7.1 我是皇帝我独苗 7.2 单例模式的定义 7.3 单例模式的应用 7.4 单例模式的扩展 7.5 最佳实践 第8章 工厂方法模式 8.1 女娲造人的故事 8.2 工厂方法模式的定义 8.3 工厂方法模式的应用 8.3.1 工厂方法模式的优点 8.3.2 工厂方法模式的使用场景 8.4 工厂方法模式的扩展 8.5 最佳实践 第9章 抽象工厂模式 9.1 女娲的失误 9.2 抽象工厂模式的定义 9.3 抽象工厂模式的应用 9.3.1 抽象工厂模式的优点 9.3.2 抽象工厂模式的缺点 9.3.3 抽象工厂模式的使用场景 9.3.4 抽象工厂模式的注意事项 9.4 最佳实践 第10章 模板方法模式 10.1 辉煌工程—制造悍马 10.2 模板方法模式的定义 10.3 模板方法模式的应用 10.4 模板方法模式的扩展 10.5 最佳实践 第11章 建造者模式 11.1 变化是永恒的 11.2 建造者模式的定义 11.3 建造者模式的应用 11.4 建造者模式的扩展 11.5 最佳实践 第12章 代理模式 12.1 我是游戏至尊 12.2 代理模式的定义 12.3 代理模式的应用 12.3.1 代理模式的优点 12.3.2 代理模式的应用 12.4 代理模式的扩展 12.4.1 普通代理 12.4.2 强制代理 12.4.3 代理是有个性的 12.4.4 虚拟代理 12.4.5 动态代理 12.5 最佳实践 第13章 原型模式 13.1 个性化电子账单 13.2 原型模式的定义 13.3 原型模式的应用 13.3.1 原型模式的优点 13.3.2 原型模式的使用场景 13.4 原型模式的注意事项 13.4.1 构造函数不会被执行 13.4.2 浅拷贝和深拷贝 13.4.3 clone与final两个冤家 13.5 最佳实践 第14章 中介者模式 14.1 进销存管理是这个样子的吗? 14.2 中介者模式的定义 14.3 中介者模式的应用 14.4 中介者模式的实际应用 14.5 最佳实践 第15章 命令模式 15.1 项目经理也难当 15.2 命令模式的定义 15.3 命令模式的应用 15.3.1 命令模式的优点 15.3.2 命令模式的缺点 15.3.3 命令模式的使用场景 15.4 命令模式的扩展 15.4.1 未讲完的故事 15.4.2 反悔问题 15.5 最佳实践 第16章 责任链模式 16.1 古代妇女的枷锁—“三从四德” 16.2 责任链模式的定义 16.3 责任链模式的应用 16.3.1 责任链模式的优点 16.3.2 责任链模式的缺点 16.3.3 责任链模式的注意事项 16.4 最佳实践 第17章 装饰模式 17.1 罪恶的成绩单 17.2 装饰模式的定义 17.3 装饰模式应用 17.3.1 装饰模式的优点 17.3.2 装饰模式的缺点 17.3.3 装饰模式的应用 17.4 最佳实践 第18章 策略模式 18.1 刘备江东娶妻,赵云他容易吗 18.2 策略模式的定义 18.3 策略模式的应用 18.3.1 策略模式的优点 18.3.2 策略模式的缺点 18.3.3 策略模式的应用 18.3.4 策略模式的注意事项 18.4 策略模式的扩展 18.5 最佳实践 第19章 适配器模式 19.1 业务发展—上帝才能控制 19.2 适配器模式的定义 19.3 适配器模式的应用 19.3.1 适配器模式的优点 19.3.2 适配器模式的应用 19.3.3 适配器模式的注意事项 19.4 适配器模式的扩展 19.5 最佳实践 第20章 迭代器模式 20.1 整理项目信息—苦差事 20.2 迭代器模式的定义 20.3 迭代器模式的应用 20.4 最佳实践 第21章 组合模式 21.1 公司的人事架构是这样的吗 21.2 组合模式的定义 21.3 组合模式的应用 21.3.1 组合模式的优点 21.3.2 组合模式的缺点 21.3.3 组合模式的应用 21.3.4 组合模式的注意事项 21.4 组合模式的扩展 21.4.1 真实的组合模式 21.4.2 透明的组合模式 21.4.3 组合模式的遍历 21.5 最佳实践 第22章 观察者模式 22.1 韩非子身边的卧底是谁派来的 22.2 观察者模式的定义 22.3 观察者模式的应用 22.3.1 观察者模式的优点 22.3.2 观察者模式的缺点 22.3.3 观察者模式的应用 22.3.4 观察者模式的注意事项 22.4 观察者模式的扩展 22.4.1 Java世界中的观察者模式 22.4.2 项目中真实观察者模式 22.4.3 订阅发布模型 22.5 最佳实践 第23章 门面模式 23.1 我要投递信件 23.2 门面模式的定义 23.3 门面模式的应用 23.3.1 门面模式的优点 23.3.2 门面模式的缺点 23.3.3 门面模式的应用 23.4 门面模式的注意事项 23.4.1 一个子系统可以有多个门面 23.4.2 门面不参与子系统内的业务逻辑 23.5 最佳实践 第24章 备忘录模式 24.1 如此追女孩子,你还不乐 24.2 备忘录模式的定义 24.3 备忘录模式的应用 24.3.1 备忘录模式的应用 24.3.2 备忘录模式的注意事项 24.4 备忘录模式的扩展 24.4.1 clone方式的备忘录 24.4.2 多状态的备忘录模式 24.4.3 多备份的备忘录 24.4.4 封装得更好一点 24.5 最佳实践 第25章 访问者模式 25.1 员工的隐私何在? 25.2 访问者模式的定义 25.3 访问者模式的应用 25.3.1 访问者模式的优点 25.3.2 访问者模式的缺点 25.3.3 访问者模式的应用 25.4 访问者模式的扩展 25.4.1 统计功能 25.4.2 多个访问者 25.4.3 双分派 25.5 最佳实践 第26章 状态模式 26.1 城市的纵向发展功臣—电梯 26.2 状态模式的定义 26.3 状态模式的应用 26.3.1 状态模式的优点 26.3.2 状态模式的缺点 26.3.3 状态模式的应用 26.3.4 状态模式的注意事项 26.4 最佳实践 第27章 解释器模式 27.1 四则运算你会吗 27.2 解释器模式的定义 27.3 解释器模式的应用 27.3.1 解释器模式的优点 27.3.2 解释器模式的缺点 27.3.3 解释器模式使用的场景 27.3.4 解释器模式的注意事项 27.4 最佳实践 第28章 享元模式 28.1 内存溢出,司见惯 28.2 享元模式的定义 28.3 享元模式的应用 28.3.1 享元模式优点和缺点 28.3.2 享元模式的应用 28.4 享元模式的扩展 28.4.1 线程安全的问题 28.4.2 性能平衡 28.5 最佳实践 第29章 桥梁模式 29.1 我有一个梦想…… 29.2 桥梁模式的定义 29.3 桥梁模式的应用 29.3.1 桥梁模式的优点 29.3.2 桥梁模式的应用 29.3.3 桥梁模式的注意事项 29.4 最佳实践 第三部分 谁的地盘谁做主—模式PK篇 第30章 创建类模式大PK 30.1 工厂方法模式VS建造者模式 30.1.1 按工厂方法建造超人 30.1.2 按建造者模式建造超人 30.1.3 最佳实践 30.2 抽象工厂模式VS建造者模式 30.2.1 按抽象工厂模式生产车辆 30.2.2 按建造者模式生产车辆 30.2.3 最佳实践 第31章 结构类模式大PK 31.1 代理模式VS装饰模式 31.1.1 代理模式 31.1.2 装饰模式 31.1.3 最佳实践 31.2 装饰模式VS适配器模式 31.2.1 按装饰模式描述丑小鸭 31.2.2 按适配器模式实现丑小鸭 31.2.3 最佳实践 第32章 行为类模式大PK 32.1 命令模式VS策略模式 32.1.1 策略模式实现压缩算法 32.1.2 命令模式实现压缩算法 32.1.3 小结 32.2 策略模式VS状态模式 32.2.1 策略模式实现人生 32.2.2 状态模式实现人生 32.2.3 小结 32.3 观察者模式VS责任链模式 32.3.1 责任链模式实现DNS解析过程 32.3.2 触发链模式实现DNS解析过程 32.3.3 小结 第33章 跨战区PK 33.1 策略模式VS桥梁模式 33.1.1 策略模式实现邮件发送 33.1.2 桥梁模式实现邮件发送 33.1.3 最佳实践 33.2 门面模式VS中介者模式 33.2.1 中介者模式实现工资计算 33.2.2 门面模式实现工资计算 33.2.3 最佳实践 33.3 包装模式群PK 33.3.1 代理模式 33.3.2 装饰模式 33.3.3 适配器模式 33.3.4 桥梁模式 33.3.5 最佳实践 第四部分 完美世界—混编模式 第34章 命令模式+责任链模式 34.1 搬移UNIX的命令 34.2 混编小结 第35章 工厂方法模式+策略模式 35.1 迷你版的交易系统 35.2 混编小结 第36章 观察者模式+中介者模式 36.1 事件触发器的开发 36.2 混编小结 第37章 规格模式 37.1 规格模式的实现 37.2 最佳实践 第38章 MVC框架 38.1 MVC框架的实现 38.1.1 MVC的系统架构 38.1.2 模型管理器 38.1.3 值栈 38.1.4 视图管理器 38.1.5 工具类 38.2 最佳实践 附录:23个设计模式
### Java命令模式Command Pattern)的实现与示例 #### 1. 命令模式的核心概念 命令模式是一种行为型设计模式,其核心目标是将请求封装为一个对象,从而使不同类型的请求可以被参数化处理。这种方式不仅实现了请求发送者和接收者的解耦[^2],还提供了诸如撤销、重做以及日志记录等功能的支持。 #### 2. 核心角色及其职责 以下是命令模式的主要组成部分及其作用: - **命令接口(Command Interface)**: 定义了一个 `execute()` 方法用于执行命令,还可以定义 `undo()` 方法用于撤销命令。 - **具体命令(Concrete Command)**: 实现了命令接口,并绑定了具体的接收者与其操作方法。 - **接收者(Receiver)**: 执行实际的操作逻辑。 - **调用者(Invoker)**: 负责触发命令的执行,通常会持有某个命令对象的引用。 - **客户端(Client)**: 创建具体命令对象并将其与相应的接收者关联起来[^4]。 #### 3. 遥控器控制家电的经典示例 ##### 步骤 1:定义命令接口 ```java public interface Command { void execute(); } ``` ##### 步骤 2:实现接收者(家电类) 假设我们有一个简单的电灯作为接收者: ```java public class Light { public void turnOn() { System.out.println("Light is ON"); } public void turnOff() { System.out.println("Light is OFF"); } } ``` ##### 步骤 3:实现具体命令类 针对上述电灯的功能,分别创建打开和关闭的具体命令: ```java public class TurnOnLightCommand implements Command { private final Light light; public TurnOnLightCommand(Light light) { this.light = light; } @Override public void execute() { light.turnOn(); } } public class TurnOffLightCommand implements Command { private final Light light; public TurnOffLightCommand(Light light) { this.light = light; } @Override public void execute() { light.turnOff(); } } ``` ##### 步骤 4:实现调用者(遥控器) 遥控器作为一个调用者,负责存储当前的命令并通过按钮触发该命令: ```java public class RemoteControl { private Command command; public void setCommand(Command command) { this.command = command; } public void pressButton() { if (command != null) { command.execute(); } else { System.out.println("No command set."); } } } ``` ##### 步骤 5:客户端调用 最后,在客户端中完成整个流程的组装和测试: ```java public class Client { public static void main(String[] args) { // 接收者 Light livingRoomLight = new Light(); // 具体命令 Command onCommand = new TurnOnLightCommand(livingRoomLight); Command offCommand = new TurnOffLightCommand(livingRoomLight); // 调用者 RemoteControl remote = new RemoteControl(); // 设置并执行开灯命令 remote.setCommand(onCommand); remote.pressButton(); // 输出: Light is ON // 设置并执行关灯命令 remote.setCommand(offCommand); remote.pressButton(); // 输出: Light is OFF } } ``` #### 4. 支持宏命令(批量操作) 为了支持更复杂的场景,比如一次执行多个命令,可以通过引入宏命令来实现。下面是一个简单示例: ##### 步骤 1:定义宏命令类 ```java import java.util.ArrayList; import java.util.List; public class MacroCommand implements Command { private List<Command> commands = new ArrayList<>(); public void addCommand(Command command) { commands.add(command); } public void removeCommand(Command command) { commands.remove(command); } @Override public void execute() { for (Command cmd : commands) { cmd.execute(); } } } ``` ##### 步骤 2:客户端使用宏命令 ```java public class ClientWithMacro { public static void main(String[] args) { Light kitchenLight = new Light(); Light bedroomLight = new Light(); Command kitchenOn = new TurnOnLightCommand(kitchenLight); Command kitchenOff = new TurnOffLightCommand(kitchenLight); Command bedroomOn = new TurnOnLightCommand(bedroomLight); Command bedroomOff = new TurnOffLightCommand(bedroomLight); MacroCommand macroCommand = new MacroCommand(); macroCommand.addCommand(kitchenOn); macroCommand.addCommand(bedroomOn); RemoteControl remote = new RemoteControl(); remote.setCommand(macroCommand); remote.pressButton(); // 同时开启厨房和卧室灯光 } } ``` #### 5. 总结 通过以上实例可以看出,命令模式在分离请求发起方与执行方的同时,也增强了系统的灵活性和可维护性。然而需要注意的是,过多的命令可能会导致系统变得臃肿,因此应权衡利弊合理应用。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值