command

第十六章 命令模式(Command Pattern)

1 概要

命令模式(Command Pattern)是一种行为模式(Behavior Design Patters)。它的设计初衷是将请求封装在对象中,以对象的形成传递给处理者。通过对象封装,请求中的参数可获得更好的保护;处理者也更容易获取请求中的数据,使得代码更加清晰,易于维护。在大型的项目中,开发人员经常会遇到这样的应用场景:当某一事件触发时,运行对应的一段程序。这个事件可能是服务器收到了客户端的一个请求,或者应用程序中定时器触发了一个超时事件。有时,这个事件的数据结构较为复杂。因此,使用命令模式能有效的帮助开发人员降低开发的难度。

命令模式的核心思想是将请求包装在一个命令对象中,然后调用处理这个命令的接口方法。根据面向对象程序设计中的多态特性(Polymorphism),程序会根据命令的类型分别执行相应的处理代码。

2 命令模式的结构

在命令模式中,有四个参与方。

  1. Command接口用于抽象一条命令。
  2. ConcreteCommand类实现了Command接口,用于表示一条具体的命令。
  3. Receiver类是真正执行这条命令的类,它实现了命令对应的处理逻辑。
  4. Invoker(客户)接收到请求后,将请求包装成命令对象,并调用Command接口中的execute()方法,触发命令的执行。

图一 命令模式结构

图一 命令模式结构。

3 命令模式示例

我们使用一个课程注册的例子来展示命令模式。首先,我们定义了Command接口。它包含一个成员方法execute(),用于完成课程注册。其参数studentId唯一指定一名学生,courseName则唯一指定一门课程。

public interface Command {
    public void execute(String studentId, String courseName);
}

RegisterCourseCommand表示的是注册一门课程的请求。注册课程的逻辑由CourseRegistrationProcessor实现。因此,在execute()方法中会调用该Processor的process()方法。当课程尚未满员时,process()方法返回true,否则返回false。

public class RegisterCourseCommand implements Command {
    private CourseRegistrationProcessor processor = null;

    public RegisterCourseCommand(CourseRegistrationProcessor processor) {
        this.processor = processor;
    }

    @Override
    public void execute(String studentId, String courseName) {
        this.processor.process();
    }
}

public class CourseRegistrationProcessor {
    public Boolean process(String studentId, String courseName) {
        Course course = CourseDb.find(courseName);
        
        if (course.size() < course.capacity()) { // 如果课程尚未注册满员
            System.out.println("Registration succeeded.");
            return true;
        } else {
            System.out.println("Registration failed because the course is full.");
            return false;
        }
    }
}

RegisterLabCommand用于表示注册一门实验课程的请求。注册实验课程的逻辑由LabRegistrationProcessor实现。当实验设备尚有空余时,process()方法返回true,否则返回false。

public class RegisterLabCommand implements Command {
    private LabRegistrationProcessor processor = null;

    public RegisterLabCommand(CourseRegistrationProcessor processor) {
        this.processor = processor;
    }

    @Override
    public void execute(String studentId, String courseName) {
        processor.process();
    }
}

public class LabRegistrationProcessor {
    public Boolean process(String studentId, String courseName) {
        Lab lab = LabDb.find(courseName);
        if (lab.size() < lab.equipmentCount()) { // 如果实验设备尚有空余
            System.out.println("Registration succeeded.");
            return true;
        } else {
            System.out.println("Registration failed because all equipments have been reserved.");
            return false;
        }
    }
}

那么,当CommandInvoker接收到请求后,它会首先将请求参数包装成一个Command对象,然后再进行相应的处理。

public class ComamndInvoker {
    public void register(String courseType, String courseName, String studentId) {
        Command cmd = null;
        if ("course".equals(courseType)) {
            CourseRegistrationProcessor processor = new CourseRegistrationProcessor();
            cmd = new RegisterCourseCommand(processor);
        } else if ("lab".equals(courseTYpe)) {
            LabRegistrationProcessor processor = new LabRegistrationProcessor();
            cmd = new RegisterLabCommand(processor);
        } else {
            throw new IllegalArgumentException("Unknown course type.");
        }

        cmd.execute(courseName, studentId);
    }
}

4 小结

本章介绍了命令模式的结构和使用方法。命令模式的优点是它将请求的数据包装在对象中,使得后续的处理过程能够充分的使用面向对象程序设计的特性,增强了程序的可读性和可维护性。

 

上一章
下一章

注册用户登陆后可留言

Copyright  2019 Little Waterdrop, LLC. All Rights Reserved.