大聪明教你学Java设计模式 | 第十六篇:命令模式

239 阅读5分钟

前言

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情

🍊作者简介: 不肯过江东丶,一个来自二线城市的程序员,致力于用“猥琐”办法解决繁琐问题,让复杂的问题变得通俗易懂。

🍊支持作者: 点赞👍、关注💖、留言💌~

大聪明在写代码的过程中发现设计模式的影子是无处不在,设计模式也是软件开发人员在软件开发过程中面临的一般问题的解决方案。大聪明本着“独乐乐不如众乐乐”的宗旨与大家分享一下设计模式的学习心得。

命令模式

🍓🍓什么是命令模式🍓🍓

在讲命令模式之前,我们先来看一下它的定义👇

命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

其实命令模式也很好理解,它将一个请求封装成一个对象,从而使调用者可以用不同的请求对客户进行参数化。在我们开发系统软件的时候,“方法的请求者”与“方法的实现者”之间经常存在紧密的耦合关系,这不利于软件功能的扩展与维护。比如,我们想对方法进行撤销、重做等处理都很不方便,所以我们就可以通过命令模式来解决这个问题。

在现实生活中,命令模式的例子也很多。比如天气热了,我们可以用遥控器打开空调,还可以通过遥控器调节温度,这就是命令模式,将打开空调、调节温度的请求和具体的处理过程完全解耦了。空调遥控器(命令发送者)通过按钮(具体命令)来遥控空调(命令接收者)做出具体的处理。再比如,有些喜欢炒股的小伙伴经常通过炒股软件来买卖自己的股票,当需要买卖股票时,只需要在股票列表中点击对应的股票,再选择买还是卖,就可以完成整个买卖的过程,股票软件提供的股票信息列表就相当于把请求和处理进行了解耦,这就是命令模式的体现。

通过上面的例子我们可以总结出实现命令模式所需要的几个角色:

  • 抽象命令类(Command)角色:声明执行命令的接口,拥有执行命令的抽象方法。
  • 具体命令类(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
  • 接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
  • 请求者(Invoker)角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。

🍓🍓命令模式的实现🍓🍓

下面我们就用命令模式,实现一下上面提到的买卖股票的例子👇

🍎🍎创建一个命令接口🍎🍎

/**
 * 命令接口
 * @description: Order
 * @author: 庄霸.liziye
 * @create: 2022-04-17 14:14
 **/
public interface Order {
    void execute();
}

🍎🍎创建一个具体的请求类🍎🍎

/**
 * 具体请求类
 * @description: Stock
 * @author: 庄霸.liziye
 * @create: 2022-04-17 14:15
 **/
public class Stock {

    /**
     * 股票名
     */
    private String name = "一只超级好的股票";

    /**
     * 股票数量
     */
    private int quantity = 10;

    public void buy(){
        System.out.println("股票操作: [ 股票名: "+name+", 股票数量: " + quantity +" ] 买入");
    }
    public void sell(){
        System.out.println("股票操作: [ 股票名: "+name+", 股票数量: " + quantity +" ] 卖出");
    }
}

🍎🍎实现 Order 接口🍎🍎

/**
 * 实现Order接口
 * @description: BuyStock
 * @author: 庄霸.liziye
 * @create: 2022-04-17 14:18
 **/
class BuyStock implements Order{
    private Stock abcStock;

    public BuyStock(Stock abcStock){
        this.abcStock = abcStock;
    }

    @Override
    public void execute() {
        abcStock.buy();
    }
}

class SellStock implements Order {
    private Stock abcStock;

    public SellStock(Stock abcStock){
        this.abcStock = abcStock;
    }

    @Override
    public void execute() {
        abcStock.sell();
    }
}

🍎🍎创建命令调用类🍎🍎

import java.util.ArrayList;
import java.util.List;

/**
 * 命令调用类
 * @description: Broker
 * @author: 庄霸.liziye
 * @create: 2022-04-17 14:20
 **/
public class Broker {
    private List<Order> orderList = new ArrayList<Order>();

    public void takeOrder(Order order){
        orderList.add(order);
    }

    public void placeOrders(){
        for (Order order : orderList) {
            order.execute();
        }
        orderList.clear();
    }
}

🍎🍎使用 Broker 类来接受并执行命令🍎🍎

/**
 * @description: Test
 * @author: 庄霸.liziye
 * @create: 2022-04-11 11:31
 **/
public class Test {

    public static void main(String[] args) {
        Stock abcStock = new Stock();

        BuyStock buyStockOrder = new BuyStock(abcStock);
        SellStock sellStockOrder = new SellStock(abcStock);

        Broker broker = new Broker();
        broker.takeOrder(buyStockOrder);
        broker.takeOrder(sellStockOrder);

        broker.placeOrders();
    }
}

🍎🍎运行结果🍎🍎 在这里插入图片描述

🍓🍓命令模式的优、缺点🍓🍓

最后我们总结一下命令模式的优点与缺点👇

🍌🍌优点🍌🍌

🍋 降低了系统耦合度;新的命令可以很容易添加到系统中去,甚至可以结合组合模式进行命令的组合,实现宏命令。

关于组合模式的介绍,各位小伙伴可以移步至大聪明教你学Java设计模式 | 第十篇:组合模式

🍌🍌缺点🍌🍌

🥝 可能产生大量具体的命令类。因为每一个具体操作都需要设计一个具体命令类,这会增加系统的复杂性;为了实现命令模式需要引入其他类,在一定程度上也增加了系统的理解难度。

小结

本人经验有限,有些地方可能讲的没有特别到位,如果您在阅读的时候想到了什么问题,欢迎在评论区留言,我们后续再一一探讨🙇‍

希望各位小伙伴动动自己可爱的小手,来一波点赞+关注 (✿◡‿◡) 让更多小伙伴看到这篇文章~ 蟹蟹呦(●'◡'●)

如果文章中有错误,欢迎大家留言指正;若您有更好、更独到的理解,欢迎您在留言区留下您的宝贵想法。

爱你所爱 行你所行 听从你心 无问东西