行为型模式-命令模式

Posted 风流 少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了行为型模式-命令模式相关的知识,希望对你有一定的参考价值。

定义

将一个请求封装为一个对象,使得发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储、传递、调用、增加与管理。

当对象A中的方法需要调用对象B中的方法时我们可以直接在A方法中创建一个B对象,然后通过B对象来直接调用。方法调用我们一般都是这么写,但是这么写会使得A要强依赖于B,名利模式就是为了解耦A与B。

对象方法调用

@Data
public class Order 
    /** 餐桌号 */
    private int diningTable;
    /** 食物名和数量 */
    private Map<String, Integer> foodDir = new HashMap<>();

    public void putFood(String name, int num) 
        foodDir.put(name, num);
    

/** 厨师 */
public class Chef 
    public void makeFood(String foodName, int num) 
        System.out.println("制作食物:" + foodName + ", 份数:" + num);
    

/**
 * 服务员点餐
 */
public class Waiter 
    public void orderFood(Order order) 
        // 1.创建厨师对象
        Chef chef = new Chef();
        order.getFoodDir().forEach((foodName, num) -> 
            // 2.调用厨师中的制作食物方法
            chef.makeFood(foodName, num);
        );
    

public class Test 
    public static void main(String[] args) 
        Order order = new Order();
        order.setDiningTable(1);
        order.putFood("鸡蛋面", 1);
        order.putFood("可乐", 2);

        Waiter waiter = new Waiter();
        waiter.orderFood(order);
    

方法的调用说破天也是通过对象.方法(实参); 这种方式调用的,如chef.makeFood(foodName, num)
而命令模式最终也将会使用对象.方法(实参); 这种方式来调用,只不过,命令模式会先将 对象参数封装成一个对象(Command),然后将这个对象放到List先暂存起来,等需要的时候再执行对象.方法(实参);

命令模式只是将方法的调用预先暂存起来(调用的对象和方法的实参还是要预先准备好的),等到需要执行的时候再执行而不是立即执行。

案例

餐馆下单案例:

  • 顾客把订单交给服务员
  • 服务员将订单交给厨师
  • 厨师根据订单准备餐点
// 抽象命令角色
public interface Command 
    void execute();



/**
 * 具体命令:封装调用者和方法参数列表,实现Command中的execute()来最后调用对象的真正方法
 */
public class OrderCommand implements Command 

    /** 方法调用对象 */
    private Chef chef;
    /** 方法参数 */
    private Order order;


    public OrderCommand(Chef chef, Order order) 
        this.chef = chef;
        this.order = order;
    


    /**
     * 调用对象的指定的方法
     */
    @Override
    public void execute() 
        order.getFoodDir().forEach((foodName, num) -> 
            chef.makeFood(foodName, num);
        );
    

服务员:不再直接调用厨师对应的方法,而是暂缓客户端传递过来的命令对象,然后统一执行命令中的方法。

/**
 * 服务员(请求者角色)
 */
public class Waitor 

    private List<Command> commands = new ArrayList<>();

    public void setCommand(Command command) 
        commands.add(command);
    

    public void orderUp() 
        System.out.println("服务员:大厨,来订单啦");
        for (Command command : commands) 
            if (command != null) 
                command.execute();
            
        
    

public class Client 
    public static void main(String[] args) 
        // 对象
        Chef chef = new Chef();

        // 方法实参
        Order order = new Order();
        order.setDiningTable(1);
        order.putFood("鸡蛋面", 1);
        order.putFood("可乐", 2);

        // 封装调用对象和实参
        OrderCommand cmd = new OrderCommand(chef, order);

        // 暂缓命令,并执行命令列表
        Waitor waitor = new Waitor();
        waitor.setCommand(cmd);
        waitor.orderUp();
    

对象方法的调用本来一句话就能解决的事对象.方法(实参); ,为啥要活生生的拆的骨肉分离呢?为了解耦感觉已经走🔥入魔了。

优缺点

优点:

  • 降低系统的耦合度。命令模式能将调用操作的对象与实现该操作的对象解耦。
  • 增加或删除命令非常方便。采用名利模式增加与删除名利不会影响其它类。它满足开闭原则,对扩展比较灵活。
  • 可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。
  • 方便实现undo和redo操作。

缺点:

  • 使用名利模式可能会造成某些系统有过多的具体命令类。
  • 系统结构更加复杂。

使用场景

  • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
  • 系统需要在不同时间指定请求、将请求排队和执行请求。
  • 系统需要支持命令的撤销(Undo)和恢复(Redo)操作。

JDK源码中的运用

// 抽象命令角色
public interface Runnable 
    public abstract void run();

// 具体命令
public class Thread implements Runnable 

	private Runnable target;

	 
	public synchronized void start() 
        start0();
    

	private native void start0();


以上是关于行为型模式-命令模式的主要内容,如果未能解决你的问题,请参考以下文章

Java开发中的23种设计模式详解之三:11种行为型模式

从零开始学习Java设计模式 | 行为型模式篇:命令模式

从零开始学习Java设计模式 | 行为型模式篇:命令模式

行为型模式之命令模式

行为型模式:命令模式

手撸golang 行为型设计模式 命令模式