文档章节

深入浅出设计模式——从球赛中悟命令模式

珂jack
 珂jack
发布于 04/05 18:00
字数 1460
阅读 1426
收藏 47
点赞 5
评论 8

一、命令模式概念

    命令模式,顾名思义就是向对象发出命令使其执行指定操作。具体的说就是以命令的形式发出请求交给调用对象,随后调用对象又将命令传送给需要处理这条命令的对象并让目标对象执行该命令。

    老规矩,以球赛为例,通常一支球队在比赛中,战术是随着比赛的进行更具场上的情况需要不断的变化。那么教练发出改变战术的指令就是一条命令,战术就是中间的调用对象,而球员则是执行命令的目标对象。我们简单的想象一下,如果没有战术,教练需要对场上的11个人单独指挥,一号你要做什么,二号你号你要做什么……一场比赛下来,教练疯了。有了战术的存在,教练只需要说:马上执行第一套作战方案。然后场上的队员就心领神会,一场比赛下来,轻松惬意。

二、使用场景

    对可变的行为进行处理,实现指令与行为之间的松耦合。

三、结构

    

    从上面的UML图中我们可以看出命令模式由三个部分组成:

        1. 目标对象(Action的实现类):执行命令的对象(球员)。

        2. 调用对象(Command的实现类):命令集(战术)。

        3. 请求者:发出命令的对象。

四、实现

    说了这么多,上干货。

1. 定义目标对象

    球员在场上具有的战术动作其实是相同的,只是不同的时间每个球员需要执行的具体动作是不一样的,所以我需要一个动作包(Action接口),里面包含了所有球员的动作。

public interface Action {
    void attack();  //进攻
    void defend();  //防守
    void relax();   //保持体力
}

    是不是很简单,一共就三个动作。接下来我们开始训练球员,让他们理解这三个动作。

public class Player1 implements Action {
    @Override
    public void attack() {
        System.out.println("1号球员,进攻!");
    }

    @Override
    public void defend() {
        System.out.println("1号球员,防守!");
    }

    @Override
    public void relax() {
        System.out.println("1号球员,保持体力!");
    }
}

    好了,1号球员已经领悟到了动作要领,2,3号球员跟他差不多,我就不一一教他们了。

2. 定义调用对象

    接下来我们要完成调用对象,也就是战术训练。首先需要一个接口,这个接口包含一个执行命令的方法,到时候下令者之要调用这个执行方法,目标对象就会执行相应的方法。

public interface Command {
    void executed();    //执行方法
}

    就这么简单,然后开始布置具体的战术。首先是一号战术:

public class FirstTactics implements Command {

    private Map<Class<? extends Action>, Action> playerMap;

    public FirstTactics(Map<Class<? extends Action>, Action> playerMap) {
        this.playerMap = playerMap;
        System.out.println("开始执行第一套作战方案!");
    }

    @Override
    public void executed() {
        playerMap.forEach((s, o) -> o.attack());
    }

    一号战术接受一个map,这个map就是场上球员的集合,然后executed也就是战术执行方法是让所有球员参与进攻。然后来看看二号战术:

public class SecondTactics implements Command {

    private Map<Class<? extends Action>, Action> playerMap;

    public SecondTactics(Map<Class<? extends Action>, Action> playerMap) {
        this.playerMap = playerMap;
        System.out.println("开始执行第二套作战方案!");
    }


    @Override
    public void executed() {
        Action player1 = playerMap.get(Player1.class);
        Action player2 = playerMap.get(Player2.class);
        Action player3 = playerMap.get(Player2.class);
        player1.attack();
        player2.defend();
        player3.relax();
    }

    二号战术同样接受所有球员的集合,然后它对不同的球员下达了不同的指令。

3. 请求者

    最后我们来看一下命令模式是如何工作的。好了,教练要开始发布命令了。

public class Coach {
    public static void main(String[] args) {
//        Player1 player1 = new Player1();
//        Player2 player2 = new Player2();
//        Player3 player3 = new Player3();
//
//        player1.attack();
//        player2.attack();
//        player3.attack();
//
//        player1.attack();
//        player2.defend();
//        player3.relax();
//
//        player1.attack();
//        player2.attack();
//        player3.attack();

        Map<Class<? extends Action>, Action> playerMap = new HashMap<>();
        playerMap.put(Player1.class, new Player1());
        playerMap.put(Player2.class, new Player2());
        playerMap.put(Player3.class, new Player3());

        new FirstTactics(playerMap).executed();
        new SecondTactics(playerMap).executed();
        new FirstTactics(playerMap).executed();

    }
}

    注释中的内容是在没有使用命令模式的情况下我们要执行同样的操作所需要做的步骤。在只有3个球员的情况下我们已经可以看出它的臃肿,所以直接忽视了。

    我们首先需要把场上所有的队员都加入一个类似于指令库的map里面。然后通过向战术命令中传入球员来得到想要的执行效果。我们来运行一下。

    结果很明显了,只要我们找到对应的战术,球员就会根据战术中布置的指令去执行,这就是命令模式。

五、优点

    通过上面的对比相信大家都能很清楚的看出, 命令模式降低了系统耦合度,并且如果有新的命令(战术)或者战术发生变动,我们也可以很容易去实现。

六、局限性

    如果命令太多系统中可能会存在过多的调用对象,这可能是命令模式的唯一能找出来的不足了。当然了,还是那句话:世界上没有十全十美的模式,每个设计模式都有它适用的地方,只要我们的使用方式得当,那么装饰者模式可以帮助我们写出漂亮优雅的代码。

附源码地址:https://gitee.com/jack90john/command

------------------------------------------------------------------------------

欢迎关注我的个人公众号,推送最新文章

© 著作权归作者所有

共有 人打赏支持
珂jack
粉丝 41
博文 17
码字总数 21342
作品 0
成都
后端工程师
加载中

评论(8)

zcx2001
zcx2001
二号战术中有个小bug:
Action player3 = playerMap.get(Player2.class);
这里应该是Player3.class了吧
orpherus
orpherus
有100个球员就要定义100个PlayerN吗?为什么不是100个带不同参数的实例?
Shazi199
Shazi199
普通开发者:这个地方要用什么设计模式来写?
优秀开发者:使用xx设计模式就能完美解决这个问题
顶级开发者:原来我写的这个是xx设计模式啊
行者__
行者__

引用来自“fengxingzhe”的评论

搜一下,Clojure 实现Java的23种模式

世上本无模式,自扰之
行者__
行者__
搜一下,Clojure 实现Java的23种模式
MrXionGe
MrXionGe
上面的那个 IDEA 关系图真的很好。
很多设计模式,光说,很难理解,一上关系图,思路立马清晰。
就像我们小时候做题一样,很多问题,只要一画图就迎刃而解了……
珂jack
珂jack
谢谢,其实并没有那么厉害。:smile:
Solid
Solid
将设计模式用生活中的例子来描述出来,才是真的掌握了!牛逼!
C#设计模式(2)——简单工厂模式

一、引言   这个系列也是自己对设计模式的一些学习笔记,希望对一些初学设计模式的人有所帮助的,在上一个专题中介绍了单例模式,在这个专题中继续为大家介绍一个比较容易理解的模式——简单工...

技术小胖子
2017/11/08
0
0
Java 设计模式(14) —— 复合模式

一、复合模式 模式常一起使用,组合在一个设计解决方案中 复合模式在一个解决方案中结合两个或多个模式,能解决一般性或一系列的问题 二、示例 本次设计模式讲解中无代码示例,由于复合模式是...

磊_lei
05/26
0
0
JavaScript设计模式之观察者模式

前言 准备研究一下MVVM的一些东西,由于MVVM运用了观察者模式的思想,因此翻开了《JavaScript设计模式与开发实践》一书,将观察者模式学习了一遍,顺便有对一些常用的设计模式进行一些了解,...

Srtian
05/22
0
0
迈向大牛的重要一步——掌握设计模式

IT职场的小菜经常有这样的疑问: 为什么一个相似的功能,大牛一会儿就搞定,然后悠闲地品着下午茶逛淘宝;而自己加班加点搞到天亮还做不完。 为什么用户提出需求变更后,大牛只需潇洒地敲敲键...

一枚Sir
2015/04/10
0
0
javascript 设计模式之工厂(Factory)模式

工厂模式介绍 工厂模式是一个创建型的模式,主要就是创建对象。其中工厂模式又分为简单工厂模式和抽象工厂模式。简单工厂模式是通过工厂方法确定创建 对应类型的对象。抽象工厂模式是通过子类...

hlxiong
2014/04/14
0
0
Java设计模式之抽象工厂模式

抽象工厂模式特点 抽象工厂模式与工厂模式最大的区别是每个单独的产品是一个工厂模式,而多个不同产品交互则是抽象工厂模式,抽象工厂模式通常要运用工厂模式的方法。通常,工厂模式的所有产...

断桥残雪断桥残雪
2015/08/09
0
0
简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别

转载:原地址http://www.cnblogs.com/zhangchenliang/p/3700820.html 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别 结合简单示例和UML图,讲解工厂模式简单原理。 一、引子 话说...

法斗斗
05/08
0
0
java设计模式-- 单例模式

在很久之前,也就是在大二暑假的时候,那时候看马士兵的视频教程中有提到很多的设计模式。 java的设计模式大致可以分为3大类,23种设计模式。 其中,创建型模式有5种:单例模式、建造者模式、...

爱学习的逃课君
2014/11/27
0
0
23种设计模式(12):策略模式

定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。 类型:行为类模式 类图: 策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,...

LCZ777
2014/07/09
0
0
代理模式(Proxy Pattern):动态代理 - 最易懂的设计模式解析

前言 今天我来全面总结开发中最常用的设计模式 - 代理模式中的动态代理模式 其他设计模式介绍 1分钟全面了解“设计模式” 单例模式(Singleton) - 最易懂的设计模式解析 简单工厂模式(Sim...

Carson_Ho
04/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

NNS拍卖合约

前言 关于NNS的介绍,这里就不多做描述,相关的信息可以查看NNS的白皮书http://doc.neons.name/zh_CN/latest/nns_background.html。 首先nns中使用的竞价货币是sgas,关于sgas介绍可以戳htt...

红烧飞鱼
22分钟前
0
0
从MySQL全备文件中恢复单个库或者单个表

从MySQL全备文件中恢复单个库或者单个表 提取建库语句 sed -n '/^-- Current Database: db_cms/,/^-- Current Database: `/p' backup.sql > db_cms.sql & 提取ddl sed -e'/./{H;$!d;}' -e ......

yysue
54分钟前
0
0
Java IO类库之管道流PipeInputStream与PipeOutputStream

一、java管道流介绍 在java多线程通信中管道通信是一种重要的通信方式,在java中我们通过配套使用管道输出流PipedOutputStream和管道输入流PipedInputStream完成线程间通信。多线程管道通信的...

老韭菜
今天
0
0
用Python绘制红楼梦词云图,竟然发现了这个!

Python在数据分析中越来越受欢迎,已经达到了统计学家对R的喜爱程度,Python的拥护者们当然不会落后于R,开发了一个个好玩的数据分析工具,下面我们来看看如何使用Python,来读红楼梦,绘制小...

猫咪编程
今天
0
0
Java中 发出请求获取别人的数据(阿里云 查询IP归属地)

1.效果 调用阿里云的接口 去定位IP地址 2. 代码 /** * 1. Java中远程调用方法 * http://localhost:8080/mavenssm20180519/invokingUrl.action * @Title: invokingUrl * @Description: * @ret......

Lucky_Me
今天
1
0
protobuf学习笔记

相关文档 Protocol buffers(protobuf)入门简介及性能分析 Protobuf学习 - 入门

OSC_fly
昨天
0
0
Mybaties入门介绍

Mybaties和Hibernate是我们在Java开发中应用的比较多的两个ORM框架。当然,目前Mybaties正在慢慢取代Hibernate,这是因为相比较Hibernate而言Mybaties性能更好,响应更快,更加灵活。我们在开...

王子城
昨天
2
0
编程学习笔记之python深入之装饰器案例及说明文档[图]

编程学习笔记之python深入之装饰器案例及说明文档[图] 装饰器即在不对一个函数体进行任何修改,以及不改变整体的原本意思的情况下,增加函数功能的新函数,因为这个新函数对旧函数进行了装饰...

原创小博客
昨天
0
0
流利阅读笔记33-20180722待学习

黑暗中的生物:利用奇技淫巧快活生存 Daniel 2018-07-22 1.今日导读 如果让你在伸手不见五指的黑暗当中生存,你能熬过几天呢?而大千世界,无奇不有。在很多你不知道的角落,有些生物在完全黑...

aibinxiao
昨天
6
0
Hystrix降级逻辑中如何获取触发的异常

通过之前Spring Cloud系列教程中的《Spring Cloud构建微服务架构:服务容错保护(Hystrix服务降级)》一文,我们已经知道如何通过Hystrix来保护自己的服务不被外部依赖方拖垮的情况。但是实际...

程序猿DD
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部