Windows环境下实现设计模式——命令模式(JAVA版)

我是荔园微风,作为一名在IT界整整25年的老兵,今天总结一下Windows环境下如何编程实现命令模式(设计模式)。

不知道大家有没有这样的感觉,看了一大堆编程和设计模式的书,却还是很难理解设计模式,无从下手。为什么?因为你看的都是理论书籍。

我今天就在Windows操作系统上安装好JAVA的IDE编程工具,并用JAVA语言来实现一个命令模式,真实的实现一个,你看懂代码后,自然就可以明白了。

命令模式Command Pattern(行为型设计模式)

定义:将请求发送者与请求接收者解耦,请求发送者通过命令对象来间接引用接收者,使得系统 具有更好的灵活性,可以在不修改现有系统代码的情况下,让相同的发送者对应不同的接收者。

上面定义听懂了吗?莫名其妙看不懂对吧。所以我们还是来看看实现生活中的例子。

不知道大家有没有这样的想法,当我们打开Windows系统,打开一个对话框,右上角是不是有一个关闭按钮?那么这个按钮就是一个“关闭窗口”请求的发送者。而按钮单击事件处理类则是该请求的接收者。Windows系统中大量使用这种技术来实现GUI图形界面。那这是怎么实现的呢?下面我们就来用JAVA实现一个。

为了降低系统的耦合度,将请求发送者与请求接收者解耦,可以使用命令模式来设计系统。在发送者与接收者之间引入了新的命令对象,将发送者的请求封装在命令对象中,再通过命令对象来调用接收者的方法。

命令模式的核心在于引入了命令类,通过命令类来降低发送者和接收者的耦合度,请求发送者只需指定一个命令对象,再通过命令对象来调用请求接收者的处理方法,其结构如图3所示:

       在命令模式结构图中包含Command(抽象命令类)、ConcreteCommand(具体命令类)、Invoker(调用者)、 Receiver(接收者)等4个角色。角色你可以理解成scratch编程中的角色,哈哈。抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。在实现execute()方法时,将调用接收者对象的相关操作(Action)。调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。接收者执行与请求相关的操作,它具体实现对请求的业务处理。

       命令模式的本质是对请求进行封装,一个请求对应于一个命令,将发出命令的责任和执行命令的责任分割开。每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行相应的操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求如何被接收、操作是否被执行、何时被执行,以及是怎么被执行的。

       命令模式的关键在于引入了抽象命令类,请求发送者针对抽象命令类编程,只有实现了抽象命令类的具体命令才与请求接收者相关联。在最简单的抽象命令类中只包含了一个抽象的execute()方法,每个具体命令类将一个Receiver类型的对象作为一个实例变量进行存储,从而具体指定一个请求的接收者,不同的具体命令类提供了execute()方法的不同实现,并调用不同接收者的请求处理方法。 

JAVA代码实现

public abstract class Command {
     public abstract void execute();
}


public class Invoker {
     private Command command;

     public Invoker(Command command) {
          this.command=command;
     }

     public void setCommand(Command command) {
          this.command=command;
     }

     public void call() {
          command.execute();
     }

}


public class ConcreteCommand extends Command {
     private Receiver receiver;

     public void execute() {
          receiver.action();
     }

}


public class Receiver {
     public void action() {
          //具体操作
     }
}

应用实例

我们大家在打游戏时,是不是在打之前都要去设置热键或功能键?比如有的人会把H设成换武器,有的人会把H设置成放绝招,这个看你喜好。那这个功能是怎么实现的呢,如何方便玩家设置功能键呢,就是用了命令模式。我们往下看,我们通过热键来设置用一个键,有时可以控制退出,有时可以控制提示帮助框显示。

1.功能键类,请求发送者

package designpatterns.command;

public class FunctionButton {
     private Command command;

     public void setCommand(Command command) {
          this.command=command;
     }

     public void click() {
          System.out print("单击该键:");
          command.execute();
     }
}

2.抽象命令类

package designpatterns.command;

public abstract class Command {
     public abstract void execute();
}

3.退出命令类

package designpatterns.command;

public class ExitCommand extends Command {
     private SystemExitClass seObj;

     public ExitCommand() {
          seObj=new SystemExitClass();
     }

     public void execute() {
          seObj.exit();
     }
}

4.帮助命令类

package designpatterns.command;

public class HelpCommand extends Command {
     private DisplayHelpClass hcObj;

     public HelpCommand() {
          hcObj=new DisplayHelpClass();
     }

     public void execute() {
         hcObj.display();
     }
}

5.退出系统类,请求接收者

package designpatterns.command;

public class SystemExitClass {
     public void exit() {
         System.out.println("退出");
     }
}

6.显示帮助文档类,请求接收者

package designpatterns.command;

public class DisplayHelpClass {
     public void display() {
         System.out.println("显示帮助");
     }
}

7.配置文件config.xml

<?xml version=1.0"?>
<config>
     <className>designpatterns.command.ExitCommand</className>
</config>

8.工具类

package designpatterns.command;

import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;

public class XMLUtil {
     public static Object getBean() {
          try{

               DocumentBuilderFactory dFactory=DocumentBuilderFactory.newInstance();
               DocumentBuilder builder=dFactory.newDocumentBuilder();
               Document doc;
               doc=builder.parse(new File("src//designpatterns//command//config.xml"));

               NodeList nl=doc.getElementsByTagName("className");
               Node classNode=nl.item(0).getFirstChild();
               String cName=classNode.getNodeValue();

               Class c=Class.forName(cName);
               Object obj=c.newInstance();
               return obj;

              }
             catch(Exception e) {
                     e.printStackTrace();
                     return null;
              }
     }
}

9.客户端测试类

package designpatterns.command;

public class Client {
     public static void main(String args[]) {
          FunctionButton fb=new FunctionButton();
          Command command;
          command=(Command)XMLUtil.getBean();

          fb.setCommand(command);
          fb.click();
     }
}

这个程序编译并运行后,输出结果是:

单击该键:退出

如果你要换成用这个键去产生帮助信息的效果,那你只需要修改XML配置文件就可以了,而不需要改代码。所以这个设计模式的真正用意就是帮程序员省时省力,就是这个目的。用本人自创的画图法可以认为以上类有如下执行关系。

总结

你可能不知道的是,在Windows系统环境下,由于大量使用GUI,所以在基于GUI的软件开发中,无论是电脑桌面应用还是手机移动应用,命令模式都得到了广泛的应用。要学好Windows系统的各类编程,你必须先搞懂命令模式。

当然,有时会遇到有不止一个请求接收者的情况,那就要用命令队列来实现了,Invoker原本里面只有一个command,现在要改成一个commandQueue了。

另外,命令模式还可以实现Windows系统中的Windows系统日志功能、Word里的撤销操作以及宏命令等。可以说,命令模式在Windows系统中是一个运用非常广泛的设计模式,学习各类面向对象编程的同学一定要牢牢掌握。

各位小伙伴,这次我们就说到这里,下次我们再深入研究windows环境下的设计模式,相信你一定能喜欢上windows。如果要转载我的文章请说明出处哦。

作者简介:荔园微风,1981年生,高级工程师,浙大工学硕士,软件工程项目主管,做过程序员、软件设计师、系统架构师,早期的Windows程序员,Visual Studio忠实用户,C/C++使用者,是一位在计算机界学习、拼搏、奋斗了25年的老将,经历了UNIX时代、桌面WIN32时代、Web应用时代、云计算时代、手机安卓时代、大数据时代、ICT时代、AI深度学习时代、智能机器时代,我不知道未来还会有什么时代,只记得这一路走来,充满着艰辛与收获,愿同大家一起走下去,充满希望的走下去。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值