概念
意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
何时使用:在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
如何解决:通过调用者调用接受者执行命令,顺序:调用者→接受者→命令。
代码规范
package com.lzhsite.technology.designPattern.command.GeneralDemo;
/**
* 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
* @author lzhcode
*
*/
public class ClientForGeneralDemo
{
public static void main(String[] args)
{
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker();
invoker.setCommand(command);
}
}
package com.lzhsite.technology.designPattern.command.GeneralDemo;
public interface Command
{
public void execute();
}
package com.lzhsite.technology.designPattern.command.GeneralDemo;
public class ConcreteCommand implements Command
{
private Receiver receiver = null;
private String state;
public ConcreteCommand(Receiver receiver)
{
this.receiver = receiver;
}
public void execute()
{
receiver.action();
}
}
package com.lzhsite.technology.designPattern.command.GeneralDemo;
public class Invoker
{
private Command command = null;
public void setCommand(Command command)
{
this.command = command;
}
public void runCommand()
{
command.execute();
}
}
package com.lzhsite.technology.designPattern.command.GeneralDemo;
public class Receiver
{
public void action()
{
}
}
适用场景
1.系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
2.系统需要在不同的时间指定请求、将请求排队和执行请求。
3.系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
4.系统需要将一组操作组合在一起,即支持宏命令。
优点
1.降低对象之间的耦合度。
2.新的命令可以很容易地加入到系统中。
3.可以比较容易地设计一个组合命令。
4.调用同一方法实现不同的功能
缺点
使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。
实际应用
点餐问题
定义命令接口
package com.lzhsite.technology.designPattern.command.RestaurantDemo;
public interface ICommand
{
public void execute();
public void setCook(ICook cook);
public int getTableNumber();
}
某道菜命令
package com.lzhsite.technology.designPattern.command.RestaurantDemo;
public class PorkCommand implements ICommand
{
private int tableNumber;
private ICook cook = null;
public PorkCommand(int tableNumber)
{
this.tableNumber = tableNumber;
}
public void setCook(ICook cook)
{
this.cook = cook;
}
public int getTableNumber()
{
return this.tableNumber;
}
public void execute()
{
this.cook.cook(tableNumber, "蒜泥白肉");
}
}
package com.lzhsite.technology.designPattern.command.RestaurantDemo;
public class ChopCommand implements ICommand {
private int tableNumber;
private ICook cook = null;
public ChopCommand(int tableNumber) {
this.tableNumber = tableNumber;
}
public void setCook(ICook cook) {
this.cook = cook;
}
public int getTableNumber() {
return this.tableNumber;
}
public void execute() {
this.cook.cook(tableNumber, "绿豆排骨煲");
}
}
package com.lzhsite.technology.designPattern.command.RestaurantDemo;
public class DuckCommand implements ICommand
{
private int tableNumber;
private ICook cook = null;
public DuckCommand(int tableNumber)
{
this.tableNumber = tableNumber;
}
public void setCook(ICook cook)
{
this.cook = cook;
}
public int getTableNumber()
{
return this.tableNumber;
}
public void execute()
{
this.cook.cook(tableNumber, "北京烤鸭");
}
}
点菜命令队列
package com.lzhsite.technology.designPattern.command.RestaurantDemo;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
/**
* 订单列表
*
* @author lzhcode
*
*/
public class CommandQueue {
private static Queue<ICommand> commands = new ArrayBlockingQueue<ICommand>(200);
public static void addMenu(MenuCommand menuCommand) {
for (ICommand command : menuCommand.getCommands()) {
commands.add(command);
}
}
public static void removeOneCommand() {
if (commands.size() > 0) {
commands.poll();
}
}
public static ICommand getOneCommand() {
ICommand command = null;
if (commands.size() > 0) {
command = commands.peek();
}
return command;
}
}
订单命令
package com.lzhsite.technology.designPattern.command.RestaurantDemo;
import java.util.Collection;
import java.util.concurrent.ArrayBlockingQueue;
public class MenuCommand implements ICommand
{
private Collection<ICommand> commands = new ArrayBlockingQueue<ICommand>(100);
public void addCommand(ICommand command)
{
commands.add(command);
}
public void execute()
{
CommandQueue.addMenu(this);
}
public void setCook(ICook cook)
{
}
public int getTableNumber()
{
return 0;
}
public Collection<ICommand> getCommands()
{
return this.commands;
}
}
定义菜类型接口
package com.lzhsite.technology.designPattern.command.RestaurantDemo;
public interface ICook
{
public void cook(int tableNumber, String name);
}
package com.lzhsite.technology.designPattern.command.RestaurantDemo;
public class HotCook implements ICook, Runnable {
private String name;
public HotCook(String name) {
this.name = name;
}
public void cook(int tableNumber, String name) {
int cookTime = (int) (20 * Math.random());
System.out.println(this.name + " 热菜厨师正在为 " + tableNumber + " 号桌做:" + name);
try {
Thread.sleep(cookTime);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
System.out.println(this.name + " 热菜厨师为 " + tableNumber + " 号桌做好了:" + name + ", 共计耗时 = " + cookTime + " 秒");
}
public void run() {
while (true) {
synchronized (ClientForRestaurantDemo.Lock) {
ICommand command = CommandQueue.getOneCommand();
if (command != null) {
if(command instanceof DuckCommand || command instanceof ChopCommand){
command.setCook(this);
command.execute();
CommandQueue.removeOneCommand();
}
}
}
try {
Thread.sleep(1000l);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
}
}
}
package com.lzhsite.technology.designPattern.command.RestaurantDemo;
public class ColdCook implements ICook, Runnable {
private String name;
public ColdCook(String name) {
this.name = name;
}
public void cook(int tableNumber, String name) {
int cookTime = (int) (20 * Math.random());
System.out.println(this.name + " 冷菜厨师正在为 " + tableNumber + " 号桌做:" + name);
try {
Thread.sleep(cookTime);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
System.out.println(this.name + " 冷菜厨师为 " + tableNumber + " 号桌做好了:" + name + ", 共计耗时 = " + cookTime + " 秒");
}
public void run() {
while (true) {
synchronized (ClientForRestaurantDemo.Lock) {
ICommand command = CommandQueue.getOneCommand();
if (command != null) {
if(command instanceof PorkCommand){
command.setCook(this);
command.execute();
CommandQueue.removeOneCommand();
}
}
}
try {
Thread.sleep(1000l);
} catch (InterruptedException exception) {
exception.printStackTrace();
}
}
}
}
定义服务员
package com.lzhsite.technology.designPattern.command.RestaurantDemo;
public class Waiter
{
public MenuCommand menuCommand = new MenuCommand();
public void orderDish(ICommand command)
{
menuCommand.addCommand(command);
}
public void orderOver()
{
this.menuCommand.execute();
}
}
程序启动入口
package com.lzhsite.technology.designPattern.command.RestaurantDemo;
import java.util.concurrent.locks.Lock;
/**
* 系统需要在不同的时间指定请求、将请求排队和执行请求。 系统需要将一组操作组合在一起,即支持宏命令。
*
* @author lzhcode
*
*/
public class ClientForRestaurantDemo {
public static Byte Lock = 1;
public static void main(String[] args) {
// 4个厨师同时开始工作
CookManager.runCookManager();
// 一次循环相当于一个订单
for (int i = 0; i < 5; i++) {
Waiter waiter = new Waiter();
ICommand chopCommand = new ChopCommand(i);
ICommand duckCommand = new DuckCommand(i);
ICommand porkCommand = new PorkCommand(i);
waiter.orderDish(chopCommand);
waiter.orderDish(duckCommand);
waiter.orderDish(porkCommand);
waiter.orderOver();
}
}
}
package com.lzhsite.technology.designPattern.command.RestaurantDemo;
public class CookManager {
public static void runCookManager() {
HotCook cook1 = new HotCook("张三");
HotCook cook2 = new HotCook("李四");
ColdCook cook3 = new ColdCook("王五");
ColdCook cook4 = new ColdCook("钱六");
Thread thread1 = new Thread(cook1);
thread1.start();
Thread thread2 = new Thread(cook2);
thread2.start();
Thread thread3 = new Thread(cook3);
thread3.start();
Thread thread4 = new Thread(cook4);
thread4.start();
}
}