设计模式之命令模式

1.引子

晚上下班都有吃宵夜的习惯,路过烧烤摊不禁想撸一串。这里用代码表示就是:
烧烤摊摊主:

public class Barbecuer {
 
	public void roastChickenWings(int num) {
		System.out.print( num + "串烤鸡翅...");
	}
	
	public void roastChickenLeg(int num) {
		System.out.print( num + "只烤鸡腿...");
	}
	
	public void roastHotDog(int num) {
		System.out.print( num + "根热狗...");
	}
}

这里分别用三个方法表示烤三种不同的食物,方法参数是数量。

我来到烧烤摊:

public class Client {
	public static void main(String[] args) {
		Barbecuer barbecuer = new Barbecuer();
		System.out.print("老板,我要");
		barbecuer.roastChickenWings(2);
		barbecuer.roastChickenLeg(1);
		barbecuer.roastHotDog(5);
	}
}

我要了2只烤翅,1只鸡腿和5根热狗。
貌似挺容易的。可是一到周末的晚上,撸串的人特别多,老板一个人忙不过来,不是数量错了就是没怎么熟,导致印象极差。究其原因就是,摊主充当着多种角色,他即要算账收钱,又要自己烤,导致自己忙不过来。我们在代码里虽然省略了算账了过程,但是这也说明摊主类极不合理,违背了“单一职责”原则。因此需要拆分。

假设摊主雇了一个服务员,专门来收集订单和算账,摊主自己安心烧烤就行。这里服务员是连接顾客和摊主的桥梁,起到传递消息的作用。那么这个消息其实就是顾客的订单,就是上面的“2只烤翅”、“1只鸡腿”、“5根热狗”;顾客和服务员关心的只是烤的东西,而用什么材料、怎么烤才好吃那是摊主自己的事儿,所以对于订单信息可以用类来表示,方便顾客和服务员请求,而具体的实现则在摊主类里面。用代码来表示就是:
烧烤摊摊主类不变:

public class Barbecuer {
 
	public void roastChickenWings(int num) {
		System.out.print( num + "串烤鸡翅...");
	}
	
	public void roastChickenLeg(int num) {
		System.out.print( num + "只烤鸡腿...");
	}
	
	public void roastHotDog(int num) {
		System.out.print( num + "根热狗...");
	}
}

订单接口:

public abstract class Command {

	public abstract void executCommand();
	
}

定义为接口,是对服务员隐藏细节。表示是烤鸡翅,烤鸡腿还是烤火腿肠等;

烤鸡腿类:

import com.design.command1.Barbecuer;
public class RoastChickenLeg extends Command {
	private Barbecuer barbecuer;
	private int num;   // 订单数量
	public RoastChickenLeg(Barbecuer barbecuer, int num) {
		this.barbecuer = barbecuer;
		this.num = num;
	}

	@Override
	public void executCommand() {
		barbecuer.roastChickenLeg(num);   // 具体由摊主自己来烤
	}
	
	@Override
	public String toString() {
		return num + "只烤鸡腿";    // 方便打日志
	}
}

烤鸡翅类:

import com.design.command1.Barbecuer;
public class RoastChickenWing extends Command {
	private Barbecuer barbecuer;
	private int num;
	public RoastChickenWing(Barbecuer barbecuer, int num) {
		this.barbecuer = barbecuer;
		this.num = num;
	}

	@Override
	public void executCommand() {
		barbecuer.roastChickenWings(num);
	}

	@Override
	public String toString() {
		return num + "只烤鸡翅";
	}
}

烤火腿肠类:

import com.design.command1.Barbecuer;
public class RoastHotDog extends Command {
	private Barbecuer barbecuer;
	private int num;
	public RoastHotDog(Barbecuer barbecuer, int num) {
		this.barbecuer = barbecuer;
		this.num = num;
	}

	@Override
	public void executCommand() {
		barbecuer.roastHotDog(num);
	}
	
	@Override
	public String toString() {
		return num + "只烤热狗";
	}
}

服务员类:

public class Waiter {
	
	List<Command> commandList = new ArrayList<Command>();
	// 增加订单
	public void addOrder(Command command) {
		System.out.println("新增订单:" + command + ", 订单时间:" + new Date());
		commandList.add(command);
	}
	
	// 取消订单
	public void disOrder(Command command) {
		System.out.println("取消订单:" + command + ", 订单时间:" + new Date());
		commandList.remove(command);
	}
	
	// 通知后厨
	public void notifyChief(){
		for (Command command : commandList) {
			command.executCommand();
		}
	}
}

服务员类里面用一个list来放置所有的订单信息,而后通过notifyChief()方法通过订单的方式给摊主。这里,我们通过Command接口对摊主类进行解耦,屏蔽了实现的细节,而后只需要扩展Command接口即可。另外通过addOrder()和disOrder()方法来增加和取消订单。

客人类:

import com.design.command1.Barbecuer;
public class Client {
	public static void main(String[] args) {
		Barbecuer barbecuer = new Barbecuer();   // 摊主对象
		RoastChickenLeg roastChickenLeg = new RoastChickenLeg(barbecuer, 10);   // 10只鸡腿
		RoastChickenWing roastChickenWing = new RoastChickenWing(barbecuer, 5); // 5只鸡翅 
		RoastHotDog roastHotDog = new RoastHotDog(barbecuer, 2);    // 2根热狗
		
		Waiter xiaoMing = new Waiter();   
		xiaoMing.addOrder(roastChickenLeg);
		xiaoMing.addOrder(roastChickenWing);
		xiaoMing.addOrder(roastHotDog);
		
		xiaoMing.notifyChief();   // 服务员xiaoMing通知摊主
		
		System.out.println();
		System.out.println("=============================");
		xiaoMing.disOrder(roastChickenLeg);   // 取消鸡腿
	}
}

运行结果:

新增订单:10只烤鸡腿, 订单时间:Tue Dec 04 23:13:05 CST 2018
新增订单:5只烤鸡翅, 订单时间:Tue Dec 04 23:13:05 CST 2018
新增订单:2只烤热狗, 订单时间:Tue Dec 04 23:13:05 CST 2018
10只烤鸡腿...5串烤鸡翅...2根热狗...
=============================
取消订单:10只烤鸡腿, 订单时间:Tue Dec 04 23:13:05 CST 2018

这种模式就是命令模式。

2. 命令模式的原理

顾客通过具体命令的形式把请求提交到服务员的订单列表里,而服务员则通过接口隐藏命令的细节,通过各命令具体实现类传递给烧烤摊摊主,让他来实现烧烤的过程;这种将一个请求封装为一个对象,从而使得可把请求对象作为参数传递的情况就是命令模式。

3.命令模式的适用场景

实际中很少用到。如果需要,可以互相讨论一下诶。

4.命令模式的特点

最大的特点在于,把请求的动作作为一个对象来传递,而这个对象经过服务员通过接口给屏蔽了细节,最后由请求的这个对象传递给烧烤摊摊主。命令模式可以把服务员和烧烤摊摊主解耦。

5.参考资料

《大话设计模式》

6.源码

https://download.youkuaiyun.com/download/nobody_1/10828713

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值