设计模式二十四章经之命令模式

概述

命令模式相对于其他模式没有那么多的规定,因为它不是一个很规矩的模式。不过,正因为这一点,命令模式对比其他设计模式更为灵活。我们接触比较多的命令模式无非开关机。我们点击关机命令时,它会先暂停事件,然后结束所有进程,最后关机。也就是说我只需要点击一个关机按钮就可以做到这一系列的命令。而我们的命令模式其实也和这一样。讲一系列的动作进行请求封装,用户只需要调用一个方法,这些动作会被挨个执行。

使用场景

需要抽象出待执行的动作,然后以参数的形式提供出来。类似于过程设计中的回调机制,而命令模式正是回调机制的一个面向对象的代替品。

在不同的时刻指定、排列和执行请求。一个命令对象可以有与初始请求无关的生存期。

需要支持取消操作。

需要支持事务操作。

支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。

具体实现

假设我们现在关机,它会先后关闭浏览器,音乐和QQ,最后才会关机。现在我们来模拟一下。

public class CloseReceiver{
    public void action(){
        System.out.println("关机");
    }

    public void closeQQ(){
        System.out.println("关闭QQ");
        action();
    }

    public void closeMusic(){
        System.out.println("关闭音乐");
    }

    public void closeChrome(){
        System.out.println("关闭浏览器");
    }
}
public interface Close{
    void execute();
}
public class QQClose implements Close{
    private CloseReceiver receiver;

    public QQClose(CloseReceiver receiver){
        this.receiver=receiver;
    }

    @Override
    public void excute(){
        recevier.closeQQ();
    }
}
public class MusicClose implements Close{
    private CloseReceiver receiver;

    public MusicClose(CloseReceiver receiver){
        this.receiver=receiver;
    }

    @Override
    public void excute(){
        recevier.closeMusic();
    }
}
public class ChromeClose implements Close{
    private CloseReceiver receiver;

    public ChromeClose(CloseReceiver receiver){
        this.receiver=receiver;
    }

    @Override
    public void excute(){
        recevier.closeChrome();
    }
}
public class Invoker{
    private QQClose qqclose;
    private MusicClose musicclose;
    private ChromeClose chromeclose;

    public setQQClose(QQClose qqclose){
        this.qqclose=qqclose;
    } 

    public setMusicClose(MusicClose musicclose){
        this.musicclose=musicclose;
    }  

    public setChromeClose(ChromeClose chromeclose){
        this.chromeclose=chromeclose;
    }

    public void closeChrome(){
        chromeclose.excute();
    } 

    public void closeMusic(){
        musicclose.excute();
    }  

    public void closeQQ(){
        qqclose.excute();
    }
}
public void Client{

    public static void main(String[] args){
        CloseReceiver receiver=new CloseReceiver();
        QQClose qqclose=new QQClose(receiver);
        MusicClose musicclose=new MusicClose(receiver);
        ChromeClose chromeclose=new ChromeClose(receiver);
        Invoker invoker=new Invoker();
        invoker.closeChrome();
        invoker.closeMusic();
        invoker.closeQQ();
    }
}

最后输出:

关闭浏览器
关闭音乐
关闭QQ
关机

调用逻辑做的如此复杂是因为开发起来方便。每当增加或者修改关闭软件时,我们只需要处理CloseReceiver以及它对应的Close类即可。设计模式原则中有一个重要的原则,开闭原则。大家可以思考思考。

除此之外,命令模式可以实现记录命令的功能。如果我们在Invoker中用一个数据结构来存储这些执行的命令,以此可以知道刚才执行过什么命令,并可以在需要时恢复。

总结

在命令模式中,可以充分体验出设计模式的通病。类的膨胀。但其也有相应的优点。比如降低了系统的耦合度,新的命令可以添加到系统中去等等。

原文发布于微信公众号 - 我就是马云飞(coding_ma)

原文发表时间:2018-06-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏我的博客

YII使用命令行模式

入口文件:shell.php run(); 数据库配置文件console.php可以参考main.php 演示protected/commands/TestCo...

3353
来自专栏魏琼东

基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET - 插件接口IModule

  我们知道,要基于平台(容器)+插件的这种模式进行开发,我们必须定义一组契约,用于约束模块插件开发,也就是说,模块插件需要遵守一定的标准进行开发,才能正常被容...

2237
来自专栏iOS Developer

Bison眼中的iOS开发多线程是这样的(二)

1303
来自专栏Java帮帮-微信公众号-技术文章全总结

Java面试系列-多线程

对Java多线程技术中所有方法的详细解析 1.run()和start() 这两个方法应该都比较熟悉,把需要并行处理的代码放在run()方法中,...

2744
来自专栏游戏开发那些事

【Linux程序设计】之进程控制&守护进程

这个系列的博客贴的都是我大二的时候学习Linux系统高级编程时的一些实验程序,都挺简单的。

1462
来自专栏后端技术探索

nginx配置基础之rewrite

重写URL是非常有用的一个功能,因为它可以让你提高搜索引擎阅读和索引你的网站的能力;而且在你改变了自己的网站结构后,无需要求用户修改他们的书签,无需其他网站修改...

795
来自专栏用户2442861的专栏

linux动态库和静态库

http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520101023104745738/

1822
来自专栏Java编程技术

实战Jmeter压测Dubbo服务接口

最近在做一些业务上云的项目,其中远程Rpc调用方式我们选择了Dubbo,为便于收集压测信息,我们选择了使用Jmeter来做压测工具,本文就来简单介绍如何使用Jm...

1042
来自专栏决胜机器学习

《Redis设计与实现》读书笔记(二十九) ——Redis集群执行命令与重新分片

《Redis设计与实现》读书笔记(二十九) ——Redis集群执行命令与重新分片 (原创内容,转载请注明来源,谢谢) 一、集群中执行命令 1、节点对命令的判断 ...

3146
来自专栏乐百川的学习频道

Python学习笔记 模块介绍

模块 导入模块 Python官方教程让我们在Python解释器中练习。但是当我们结束解释器,所有的代码都消失了。如果我们希望让代码永久保存的话,就需要将它们保存...

1806

扫码关注云+社区