zoukankan      html  css  js  c++  java
  • 6 行为型模式之

    命令模式介绍:命令模式相对于其它模式来说并没有那么多的条条框框,不算是一个很“规矩”的模式,不过,就是基于这一点,命令模式相对于其它的设计模式更为灵活,我们接触比较多的命令模式无非就是菜单命令,如在操作系统中,我们点击“关机”命令,系统会执行一系列的操作,如先是暂停处理事件,保存系统的一些配置,然后结束程序进程,最后调用内核命令关闭计算机等,而我闪的命令模式也与之相似。将一系列的方法调用封装,用户只需要调用一个方法执行,那么所有这些被封装的方法就会被挨个执行调用

    命令模式定义:将一个请求封装成一个对象,从而让用户使用不同的请求把客户端参数化,对请求排队或者记录请求日志操作

    命令模式使用场景:需要抽象出待执行的动作,然后以参数的形式提供出来 -- 类似于面向过程中的回调,而命令模式正是回调的面向对象的实现。

    命令模式主要是命令的请求者与命令的执行者之间的关系,其中命令的里面保存了一个命令执行者的引用 

    下面以小时候玩的“俄罗斯方块”游戏为例子,讲解命令模式的用法。

    俄罗斯方块游戏中有4个按钮,两个左右的,一个快速落下的,还有一个是变换方块的形状的,一个玩游戏的人就相当于我们的客户端,而游戏上4个按钮就相当于4个请求者或者称为调用者,执行具体按钮命令的逻辑方法可以看作是命令角色。

    下面以代码说明。首先是命令的接收者

     1 /**
     2  * 命令接收者,俄罗斯方块游戏
     3  * 
     4  */
     5 public class TerisMachine {
     6 
     7     //真正处理"向左"操作的逻辑代码
     8     public void toLeft(){
     9         System.out.println("向左");
    10     }
    11 
    12     //真正处理"向右"操作的逻辑代码
    13     public void toRight(){
    14         System.out.println("向右");
    15     }
    16 
    17     //真正处理"快速向下"操作的逻辑代码
    18     public void fastToBottom(){
    19         System.out.println("快速向下");
    20     }
    21 
    22     //真正处理"改变形状"操作的逻辑代码
    23     public void transform(){
    24         System.out.println("改变形状");
    25     }
    26 }

     TetrisMachine类是整个命令模式中唯一处理具体代码逻辑的地方,其他的类都是直接或者间接地调用到该类的方法,这就是接收者的角色,处理具体的逻辑。

    接下来我们定义一个接口命令来作为命令角色的抽象

    1 /**
    2  * 命令角色的抽象
    3  */
    4 public interface Command {
    5     //命令执行的方法
    6     void execute();
    7 }

    下面分别实现4个命令

     1 /**
     2  * 向左移动的命令
     3  */
     4 public class LeftCommand implements Command{
     5     //持有一个命令执行者的引用
     6     TerisMachine terisMachine;
     7 
     8     public void setTerisMachine(TerisMachine terisMachine){
     9         this.terisMachine = terisMachine;
    10     }
    11 
    12     @Override
    13     public void execute() {
    14         //调用游戏机里面的方法具体执行
    15         terisMachine.toLeft();
    16     }
    17 }
     1 /**
     2  * 向右移动的命令
     3  */
     4 public class RightCommand implements Command{
     5     //持有一个命令执行者的引用
     6     TerisMachine terisMachine;
     7 
     8     public void setTerisMachine(TerisMachine terisMachine){
     9         this.terisMachine = terisMachine;
    10     }
    11 
    12     @Override
    13     public void execute() {
    14         //调用游戏机里面的方法具体执行
    15         terisMachine.toRight();
    16     }
    17 }
     1 /**
     2  * 快速向下的命令
     3  */
     4 public class FastToBottomCommand implements Command{
     5     //持有一个命令执行者的引用
     6     TerisMachine terisMachine;
     7 
     8     public void setTerisMachine(TerisMachine terisMachine){
     9         this.terisMachine = terisMachine;
    10     }
    11 
    12     @Override
    13     public void execute() {
    14         //调用游戏机里面的方法具体执行
    15         terisMachine.fastToBottom();
    16     }
    17 }
     1 /**
     2  * 改变形状的命令
     3  */
     4 public class TransformCommand implements Command{
     5     //持有一个命令执行者的引用
     6     TerisMachine terisMachine;
     7 
     8     public void setTerisMachine(TerisMachine terisMachine){
     9         this.terisMachine = terisMachine;
    10     }
    11 
    12     @Override
    13     public void execute() {
    14         //调用游戏机里面的方法具体执行
    15         terisMachine.transform();
    16     }
    17 }

    上面有个相应的4个命令了。下面再实现一个命令的请求者

     1 /**
     2  *
     3  * 命令的请求者
     4  */
     5 public class Buttons {
     6     //向左移动的命令
     7     private LeftCommand leftCommand;
     8     //向右移动的命令
     9     private RightCommand rightCommand;
    10     //快速萍的命令
    11     private FastToBottomCommand fastToBottomCommand;
    12     //改变形状的命令
    13     private TransformCommand transformCommand;
    14 
    15     //设置向左移动的命令
    16     public void setLeftCommand(LeftCommand leftCommand) {
    17         this.leftCommand = leftCommand;
    18     }
    19 
    20     //设置向右移动的命令
    21     public void setRightCommand(RightCommand rightCommand) {
    22         this.rightCommand = rightCommand;
    23     }
    24 
    25     //设置快速落下的命令
    26     public void setFastToBottomCommand(FastToBottomCommand fastToBottomCommand) {
    27         this.fastToBottomCommand = fastToBottomCommand;
    28     }
    29 
    30     //设置改变形状的命令
    31     public void setTransformCommand(TransformCommand transformCommand) {
    32         this.transformCommand = transformCommand;
    33     }
    34 
    35     //按下按钮向左移动
    36     public void toLeft(){
    37         leftCommand.execute();
    38     }
    39 
    40     //按下按钮向右移动
    41     public void toRight(){
    42         rightCommand.execute();
    43     }
    44 
    45     //按下按钮快速落下
    46     public void fall(){
    47         fastToBottomCommand.execute();
    48     }
    49 
    50     //按下按钮改变形状
    51     public void transform(){
    52         transformCommand.execute();
    53     }
    54 
    55 }

    最后由客户端来决定如何使用

    客户端类:

     1 /**
     2  * 玩家,也是客户端
     3  */
     4 public class Player {
     5     public static void main(String[] args){
     6         test1();
     7     }
     8 
     9     //测试命令模式
    10     private static void test1() {
    11         //俄罗斯方块游戏
    12         TerisMachine terisMachine = new TerisMachine();
    13 
    14         //根据游戏我们造4种命令
    15         LeftCommand leftCommand = new LeftCommand();
    16         RightCommand rightCommand = new RightCommand();
    17         FastToBottomCommand fastToBottomCommand = new FastToBottomCommand();
    18         TransformCommand transformCommand = new TransformCommand();
    19 
    20         //引用一个命令的具体执行者
    21         leftCommand.setTerisMachine(terisMachine);
    22         rightCommand.setTerisMachine(terisMachine);
    23         fastToBottomCommand.setTerisMachine(terisMachine);
    24         transformCommand.setTerisMachine(terisMachine);
    25 
    26         //按钮可以执行不同的命令
    27         Buttons buttons = new Buttons();
    28         buttons.setLeftCommand(leftCommand);
    29         buttons.setRightCommand(rightCommand);
    30         buttons.setFastToBottomCommand(fastToBottomCommand);
    31         buttons.setTransformCommand(transformCommand);
    32 
    33         //具体按下哪个键玩家说了算
    34         buttons.toLeft();
    35         buttons.toRight();
    36         buttons.fall();
    37         buttons.transform();
    38     }
    39 
    40     //对于大部分开发者来说很容易接受下面的代码
    41     private static void test2(){
    42         //俄罗斯方块游戏
    43         TerisMachine machine = new TerisMachine();
    44 
    45         //要实现怎样的控制,直接调用相应的函数就行
    46         machine.toLeft();
    47         machine.toRight();
    48         machine.fastToBottom();
    49         machine.transform();
    50     }
    51 
    52 
    53 }

    或者大家在看了这一长篇代码后心存疑惑,明明就是一个很简单的问题,为什么要做的如此复杂呢?对于大部分的开发者来说更愿意接受上面的 test2()中的代码,也就是:

         //对于大部分开发者来说很容易接受下面的代码
    41     private static void test2(){
    42         //俄罗斯方块游戏
    43         TerisMachine machine = new TerisMachine();
    44 
    45         //要实现怎样的控制,直接调用相应的函数就行
    46         machine.toLeft();
    47         machine.toRight();
    48         machine.fastToBottom();
    49         machine.transform();
    50     }

    调用逻辑做得如此复杂,这是因为开发起来方便,每次我们增加或者修改游戏功能只需要修改 TetrisMachine类就行了,然后对应的改一改Player类,一切都很方便。但是,对开发者自己来说是方便了,那么,如果有一天开发者不再负责这个项目了呢?这样的逻辑留给后来者,没有人会觉得方便。设计模式有一条很重要的原则:对修改关闭,对扩展开放。大家可以细细体会。

     

  • 相关阅读:
    flexgrid的应用
    Flexigrid例子二: 原位编辑器
    JQuery 插件FlexiGrid 之完全配置与使用
    linux 配置环境变量不生效
    redis主从和哨兵搭建
    linux 清楚buff
    linux时间ESC修改为CST格式
    mysql-5.7.26 版本,表不区分区分大小写问题
    CDH-mysql 开启关闭 gtid
    mysql-5.7.26 安装已经 主从同步复制
  • 原文地址:https://www.cnblogs.com/start1225/p/6729708.html
Copyright © 2011-2022 走看看