第十五章行为性模式—命令模式

这篇具有很好参考价值的文章主要介绍了第十五章行为性模式—命令模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式:
  • 类行为模式:采用继承机制来在类间分派行为

  • 对象行为模式:采用组合或聚合在对象间分配行为

由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。

行为型模式分为:

  • 模板方法模式
  • 策略模式
  • 命令模式
  • 职责链模式
  • 状态模式
  • 观察者模式
  • 中介者模式
  • 迭代器模式
  • 访问者模式
  • 备忘录模式
  • 解释器模式

以上 11 种行为型模式,除了模板方法模式解释器模式是类行为型模式,其他的全部属于对象行为型模式。

命令模式

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

命令模式是一种行为设计模式**,它将请求转换为一个包含与请求相关的所有信息的独立对象**,该转换让你能够根据不同的请求将方法参数化,延迟请求执行或者将其放入队列中,且能够实现可撤销操作

解决的问题

第十五章行为性模式—命令模式

  • 客户点菜是通过服务员,所以发送请求的责任属于服务员
  • 具体的菜品是厨师进行烹饪,所以执行请求的测试的属于厨师
  • 将发送请求的责任与执行请求的责任分开

结构

  • 抽象命令类(Command)角色: 定义命令的接口,声明执行的方法。
  • 具体命令(Concrete Command)角色:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
  • 实现者/接收者(Receiver)角色: 接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
  • 调用者/请求者(Invoker)角色: 要求命令对象执行请求,通常会持有命令对象可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。

实例

第十五章行为性模式—命令模式

分析命令模式的角色在该案例中由谁来充当:

  • 服务员: 就是调用者角色,由她来发起命令。
  • 资深大厨: 就是接收者角色,真正命令执行的对象。
  • 订单: 命令中包含订单。

抽象命令类

public interface Command {
    void execute();
}

具体命令类

public class OrderCommand implements  Command{
    private SeniorChef receiver;
    private Order order;
    public OrderCommand(SeniorChef receiver, Order order) {
        this.receiver = receiver;
        this.order = order;
    }
    @Override
    public void execute() {
        System.out.println(order.getDiningTable() + "桌的订单:");
        Map<String, Integer> foodDir = order.getFoodDir();
        Set<String> keys = foodDir.keySet();
        for (String foodName : keys) {
            receiver.makeFood(foodName, foodDir.get(foodName));
        }
        System.out.println(order.getDiningTable() + "桌的饭准备完毕!!!");

    }
}
/**
 * 订单类
 */
@Data
public class Order {
    // 餐桌号码
    private int diningTable;
    // 所下的餐品及份数
    private Map<String,Integer> foodDir = new HashMap<>();

    public void setFood(String name, int num) {
        foodDir.put(name,num);
    }
}

  • 聚合了接收者

接收者:资深大厨

public class SeniorChef {
    public void makeFood(String name,int num) {
        System.out.println(num + "份" + name);
    }
}

调用者:服务员

public class Waiter {
    //持有多个命令对象
    private List<Command> commands=new ArrayList<>();
    public void setCommand(Command cmd) {
        // 将命令类对象存储到list集合中
        commands.add(cmd);
    }
    // 发起命令功能: 喊 订单来了
    public void orderUp() {
        System.out.println("美女服务员:大厨,新订单来了。。。。");
        for (Command command : commands) {
            if(command != null) {
                command.execute();
            }
        }
    }
}
  • 调用者中聚合了命令对象
  • 我们这里调用者就将我们的命令对象放入了队列中,这种我们的可以命令对象进行操作,比如延迟执行,当然也可以做到了我们的撤销等操作

测试

public class Client {
    public static void main(String[] args) {
        // 创建第二个订单对象
        Order order1 = new Order();
        order1.setDiningTable(1);
        order1.setFood("西红柿鸡蛋面",1);
        order1.setFood("小杯可乐",2);
        // 创建第二个订单对象
        Order order2 = new Order();
        order2.setDiningTable(2);
        order2.setFood("尖椒肉丝盖饭",1);
        order2.setFood("小杯雪碧",1);
        //创建接收者对象 厨师
        SeniorChef receiver = new SeniorChef();
        //创建命令对象
        OrderCommand orderCommand1 = new OrderCommand(receiver, order1);
        OrderCommand orderCommand2 = new OrderCommand(receiver, order2);
        // 创建调用者(服务员对象)
        Waiter invoke = new Waiter();
        invoke.setCommand(orderCommand1);
        invoke.setCommand(orderCommand2);
        //让服务员发起命令
        invoke.orderUp();
    }
}
美女服务员:大厨,新订单来了。。。。
1桌的订单:
1份西红柿鸡蛋面
2份小杯可乐
1桌的饭准备完毕!!!
2桌的订单:
1份尖椒肉丝盖饭
1份小杯雪碧
2桌的饭准备完毕!!!

存在的问题

优点:

  • 降低系统的耦合度。命令模式能将调用操作的对象实现该操作的对象解耦。

  • 增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,它满足 “开闭原则”,对扩展比较灵活。

  • 可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。

  • 方便实现 Undo 和 Redo 操作。命令模式可以与后面介绍的备忘录模式结合,实现命令的撤销与恢复。

缺点:

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

适用场景

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

JDK 源码 - Runnable

Runable 是一个典型命令模式,Runnable 担当命令的角色,Thread 充当的是调用者,start 方法就是其执行方法

  • 调用者和接收者分离了
// 命令接口(抽象命令角色)
public interface Runnable {
	public abstract void run();
}

// 调用者
public class Thread implements Runnable {
    private Runnable target;
    
    public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }
    
    private native void start0();
}

start 方法会调用一个 native 方法 start0(),调用系统方法,开启一个线程。而接收者是对程序员开放的,可以自己定义接收者。文章来源地址https://www.toymoban.com/news/detail-467283.html

/**
 * jdk Runnable 命令模式
 * TurnOffThread:属于具体命令
 */
public class TurnOffThread implements Runnable{
     private Receiver receiver;
    
     public TurnOffThread(Receiver receiver) {
     	this.receiver = receiver;
     }
     public void run() {
     	receiver.turnOFF();
     }
}

到了这里,关于第十五章行为性模式—命令模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 第十五章 奇异值分解

    奇异值分解(SVD)是一种矩阵因子分解方法。 任意一个 m × n mtimes n m × n 矩阵,都可以表示为三个矩阵的乘积(因子分解)形式,分别是 n n n 阶正交矩阵、由降序排列的非负的对角线元素组成的 m × n mtimes n m × n 的矩形对角矩阵和 n n n 阶正交矩阵。 矩阵的奇异值分解一定

    2024年02月07日
    浏览(46)
  • 第十五章——友元、异常

    友元 类并非只能拥有友元函数,也可以将类作为友元。在这种情况下,友元类的所有方法都可以访问原始类的私有成员和保护成员。因此尽管友元被授予从外部访问类的私有部分的权限,但它们并不与面向对象的编程思想相悖,相反提高了共有接口的灵活性。 友元类  假定

    2024年02月16日
    浏览(37)
  • 第十五章 RabbitMQ 延迟队列

    实际业务中,例如秒杀系统,秒杀商品成功会有截止时间,这时需要用到RabbitMQ延迟服务。 TTL ,即 Time-To-Live,存活时间,消息和队列都可以设置存活时间 Dead Letter,即死信,若给消息设置了存活时间,当超过存活时间后消息还没有被消费,则该消息变成了死信 Dead Letter Exc

    2024年01月25日
    浏览(40)
  • [C国演义] 第十五章

    力扣链接 子数组 ⇒ dp[i]的含义: 以arr[i] 结尾的所有子数组中的最长湍流子数组的长度 子数组 ⇒ 状态转移方程根据 最后一个位置来划分 👇👇👇 初始化: 都初始化为1 ⇒ 1. 一个数字也是一个湍流子数组. 2. 可以少考虑四种状态 遍历方向: 从前往后遍历 返回结果: 返回g表 和

    2024年02月07日
    浏览(45)
  • 【OpenCV】第十五章: 模板匹配

    第十五章: 模板匹配 模板匹配就是在给定的图片中查找和模板最相似的区域。 实现的方法是:将模板在图片上滑动(从左向右,从上向下),遍历所有滑窗,计算匹配度,将所有计算结果保存在一个矩阵种,并将矩阵中匹配度最高的值作为匹配结果。 一、单模板匹配 1、匹配函

    2024年02月02日
    浏览(43)
  • WEB核心【会话技术】第十五章

    目录 💂 个人主页:  爱吃豆的土豆 🤟 版权:  本文由【爱吃豆的土豆】原创、在CSDN首发、需要转载请联系博主 💬 如果文章对你有帮助、 欢迎关注、点赞、收藏(一键三连)和订阅专栏哦 🏆 人必有所执,方能有所成! 🐋希望大家多多支持😘一起进步呀! 1,会话技术   

    2023年04月17日
    浏览(41)
  • 第十五章 Unity 角色移动旋转实例

    本章节我们创建一个“RoleDemoProject”工程,然后导入我们之前创建地形章节中的“TerrainDemo.unitypackage”资源包,这个场景很大,大家需要调整场景视角才能看清。 接下来,我们添加一个人物模型,操作方式就是将模型文件目录复制到“Assets”下 然后Unity会自动同步该文件,我

    2024年02月06日
    浏览(37)
  • 《TCP IP 网络编程》第十五章

     标准 I/O 函数的两个优点:         除了使用 read 和 write 函数收发数据外,还能使用标准 I/O 函数收发数据。下面是标准 I/O 函数的两个优点: 标准 I/O 函数具有良好的移植性 标准 I/O 函数可以利用缓冲提高性能         创建套接字时,操作系统会准备 I/O 缓冲。 此缓

    2024年02月14日
    浏览(50)
  • 【Rust】Rust学习 第十五章智能指针

    指针  ( pointer )是一个包含内存地址的变量的通用概念。这个地址引用,或 “指向”(points at)一些其他数据。Rust 中最常见的指针是第四章介绍的  引用 ( reference )。引用以   符号为标志并借用了他们所指向的值。除了引用数据没有任何其他特殊功能。它们也没有任

    2024年02月12日
    浏览(34)
  • 北大青鸟第十五章蘑菇视频案例

    实现了北大青鸟十五章蘑菇视频所有功能,复制展示的代码可以直接使用,最后底部的切换使用点击事件自行更改即可

    2024年02月08日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包