设计模式-命令模式

本文通过一个包工头指挥工人工作的例子,详细介绍了命令模式的设计理念及其应用。通过将请求封装为对象,实现请求发送者与执行者的解耦,提高代码的扩展性和维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

命令模式:将一个请求或者命令封装成一个对象,从而让用户将客户端请求参数化。对请求排队,或者记录日志,以及支持撤销动作。

每次看任何定义都是云里雾里╮(╯▽╰)╭。其实我觉得这个模式就是将要进行的请求封装成对象,为什么要封装成对象?因为这个请求可能不是一个动作能完成的,再者就是这个请求需要依赖与另外的功能类去实现,如果代码直接耦合的持有另一功能类的引用去操作实现功能,会使的代码耦合度比较高,而且不利于修改,以及不能同步去工作,假设现在那个功能类还没写完呢???怎么写持有引用的代码?必然不能啊,这个时候老司机就会想到,接口!下面我们用代码来提出问题并进行演化。

假设有一个包工头类,他要指挥工人去搬砖,铲土,摸水泥等工作,我们先来写一个包工头类。

/**
 * 包工头
 * @author PC
 *
 */
public class Labour {

	
	/**
	 * 指挥搬砖
	 */
	public void orderMovingBrick(){
		
	}
	
	/**
	 * 指挥铲土
	 */
	public void orderShovel(){
		
	}
	
	/**
	 * 指挥上水泥
	 */
	public void orderPutCement(){
		
	}
	
}


我们可以看到这个类的架子,这个时候就提出问题:

一:如果我们的搬砖工人,铲土工人,上水泥工人还没写出来怎么办?代码如何往下写?

二:假如说有了如何写? 下面是有了的代码:

修改后的代码:

//搬砖工
class BrickPerson{
	void mockingBrick(){
		
	};
}
//铲土工
class ShovelPerson{
	void shovel(){
		
	}
}
//水泥工
class CementPerson{
	void putCement(){
		
	}
}
包工头类:

/**
 * 包工头
 * @author PC
 *
 */
public class Labour {
	
	private BrickPerson brickPerson;
	private ShovelPerson shovelPerson;
	private CementPerson cementPerson;
	
	public Labour() {
		brickPerson = new BrickPerson();
		shovelPerson = new ShovelPerson();
		cementPerson = new CementPerson();
	}

	
	/**
	 * 指挥搬砖
	 */
	public void orderMovingBrick(){
		brickPerson.mockingBrick();
	}
	
	/**
	 * 指挥铲土
	 */
	public void orderShovel(){
		shovelPerson.shovel();
	}
	
	/**
	 * 指挥上水泥
	 */
	public void orderPutCement(){
		cementPerson.putCement();
	}
	
}

这样没毛病啊,看着很爽啊,哈哈哈。然后过了二个月,又出问题了。

包工头指挥搬砖不需要指挥工人了,现在新出来一批机器人可以搬砖,高效不懂累,不抱怨成本低,哈哈这时候怎么办? 有人说,那就去声明一个机器人引用,然后在orderMovingBrick方法里改一下不就得了? 那好,那我再问,现在需要指挥这个动作同时要指挥20个机器人呢,你怎么办?然后再将代码改成使用List存入20个机器人的引用,然后再movingBrick方法改成循环List调用机器人搬砖的方法?

切记:对修改闭合,对扩展开发,还有我和你讲,你这样改,这堆代码在变过三次需求之后,必须成了烂代码了,干过开发的都知道╮(╯▽╰)╭。


那么到底该肿么办?

思路:将需要执行的命令封装成一个对象。

定义一个高度抽象接口,只有执行的动作,因为命令只需要执行啊!!!:

/**
 * 命令接口
 * @author PC
 *
 */
public interface Command {

	/**
	 * 调取执行的方法
	 */
	void execute();
	
}

包工头代码:

/**
 * 包工头
 * @author PC
 *
 */
public class Labour {
	
	private Command movingBrickCommand;
	private Command shovelCommand;
	private Command putCementCommand;
	

	public Labour(Command movingBrickCommand, Command shovelCommand,
			Command putCementCommand) {
		super();
		this.movingBrickCommand = movingBrickCommand;
		this.shovelCommand = shovelCommand;
		this.putCementCommand = putCementCommand;
	}

	/**
	 * 指挥搬砖
	 */
	public void orderMovingBrick(){
		movingBrickCommand.execute();
	}
	
	/**
	 * 指挥铲土
	 */
	public void orderShovel(){
		shovelCommand.execute();
	}
	
	/**
	 * 指挥上水泥
	 */
	public void orderPutCement(){
		putCementCommand.execute();
	}
	
}

哈哈,这个时候怎么样,我跟你讲,一劳永逸,包工头代码不需要修改了。

看三个命令的实现;

/**
 * 搬砖命令
 * @author PC
 *
 */
class BrickCommand implements Command{

	private BrickPerson person;
	
	public BrickCommand(BrickPerson person) {
		this.person = person;
	}
	
	public void execute() {
		person.mockingBrick();
	}
	
}

/**
 * 铲土命令
 * @author PC
 *
 */
class ShovelCommand implements Command{

	private ShovelPerson person;
	
	public ShovelCommand(ShovelPerson person) {
		this.person = person;
	}
	
	public void execute() {
		person.shovel();
	}
	
}

/**
 * 上水泥命令
 * @author PC
 *
 */
class PutCementCommand implements Command{

	private CementPerson person;
	
	public PutCementCommand(CementPerson person) {
		this.person = person;
	}
	
	public void execute() {
		person.putCement();
	}
	
}

别着急骂,再看调用端:

public class Client {

	public static void main(String[] args) {
		BrickCommand brickCommand = new BrickCommand(new BrickPerson());
		ShovelCommand shovelCommand = new ShovelCommand(new ShovelPerson());
		PutCementCommand cementCommand = new PutCementCommand(new CementPerson());
		
		Labour labour = new Labour(brickCommand, shovelCommand, cementCommand);
		
		labour.orderMovingBrick();
		labour.orderShovel();
		labour.orderPutCement();
		
	}
	
}

有人会说,这岂不是变复杂了??!!这图什么?代码变得这么多?

这其实是设计模式的大体思想,其实几乎不管什么设计模式,他都要尽力做到这样的效果:

低耦合,对修改闭合,对扩展开放,不要去修改以前的功能实现代码,如果功能需要改变或者升级,最好的效果是仅去修改调用端的代码,而且允许因为功能的改变而产生的代码变多的问题,以及以前功能代码变得无用的问题(可以加过期或者删除),但是不接受去直接修改功能实现代码。


那这个时候去解决我们开始没使用命令模式而产生的问题,假如要换成机器人搬砖呢,并且是20个机器人呢?

定义机器人类;

class Rebot {
	void movingBrick(){
		System.out.println("机器人在搬砖...");
	};
}

定义机器人搬砖命令:

/**
 * 机器人搬砖
 * @author PC
 *
 */
class RebotMovingBrick implements Command{

	private List<Rebot> list = new ArrayList<Rebot>();
	
	public RebotMovingBrick(List<Rebot> list) {
		super();
		list.addAll(list);
	}



	public void execute() {
		for (Rebot rebot : list) {
			rebot.movingBrick();
		}
	}
	
}

调用段代码:

public class Client {

	public static void main(String[] args) {
//		BrickCommand brickCommand = new BrickCommand(new BrickPerson());
		RebotMovingBrick brickCommand = new RebotMovingBrick(list);
		ShovelCommand shovelCommand = new ShovelCommand(new ShovelPerson());
		PutCementCommand cementCommand = new PutCementCommand(new CementPerson());
		
		Labour labour = new Labour(brickCommand, shovelCommand, cementCommand);
		
		labour.orderMovingBrick();
		labour.orderShovel();
		labour.orderPutCement();
		
	}
	
}

看到没,只需要重新组装一个命令就行了,原本的代码,包工头代码完全没动!以及曾经涉及到的工人代码等等的都完全没有去修改,这是极好的,你新做的功能就只需要关注自己新做的这两个类就行了,然后一组装之后丢该包工头就行了。就算出错了,你也不用去关注其他的代码,就去检查自己的代码就行了(当然,这个包工头架构本身是没问题的)。


总结命令模式;

将命令的调用者与执行者来通过接口隔离。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值