This is the 8th day of my participation in the August More text Challenge. For details, see: August More Text Challenge

0 x0, introduction

😊 Again on Friday, wait for the weekend, continue to study the beauty of design patterns, this article corresponding to the design patterns and paradigms: behavior Pattern (71), Command Pattern (71), also is not often used in the work of the Pattern, you can learn about ~

Tips: Second-hand knowledge processing is hard to avoid mistakes, interested in time can be consulted by themselves, thank you.


0 x1, definition

The original definition

Encapsulating a request (command) into an object allows us to parameterize other objects with different requests (dependency injection), and supports queuing, logging, undoing, and so on of requests (additional control).

When it comes to code implementation, the command mode is the most important way to encapsulate functions as objects that can be passed. Consider this when your programming language does not support passing functions as arguments. The advantages of command mode are that functions can be encapsulated as objects, and can be stored and executed

0x2. Write a simple example

Let’s write an example of music playback control in command mode. First, the business entity:

public class Music {
    private String name;
    private String url;

    public Music(String name, String url) {
        this.name = name;
        this.url = url;
    }

    public String getName(a) { return name; }
    public String getUrl(a) { returnurl; }}Copy the code

Next go to the abstract command class → declare the action to do:

public interface ICommand {
    void execute(a);
}
Copy the code

Then go to the abstract receiver → declare the command to execute and provide it to the client:

public interface IPlayer {
    void setPlayList(List<Music> musics);
    void play(a);
    void play(int cursor);
    void next(a);
    void pre(a);
    void pause(a);
}
Copy the code

Implement an abstract command class, store a receiver, and delegate to the receiver to execute the specific method when invoking the specific command:

public class SetPlayListCommand implements ICommand {
    private final IPlayer player;
    private List<Music> musics;
    
    public SetPlayListCommand(IPlayer player) { this.player = player; }
    
    @Override public void execute(a) { player.setPlayList(musics); }
    
    public void setPlayList(List<Music> musics) { this.musics = musics; }}public class PlayCommand implements ICommand {
    private final IPlayer player;

    public PlayCommand(IPlayer player) { this.player = player; }

    @Override public void execute(a) { player.play(); }}public class NextCommand implements ICommand {
    private final IPlayer player;

    public NextCommand(IPlayer player) { this.player = player; }

    @Override public void execute(a) { player.next(); }}// The other two commands are similar, but call different player methods...
Copy the code

Then go to the concrete receiver → implement the abstract receiver, receive the command and execute the real code logic:

public class MusicPlayer implements IPlayer {
    private int cursor = -10000; // The cursor is currently playing
    private int pauseCursor = -10000; // Pause the cursor currently
    private final List<Music> musics = new ArrayList<>();

    @Override
    public void setPlayList(List<Music> musics) {
        this.musics.clear();
        if(musics == null || musics.isEmpty()) {
            System.out.println("Set playlists cannot be empty!");
        } else {
            this.musics.addAll(musics);
            this.cursor = -10000;
            System.out.println("List set successfully, current track:");
            for(Music music: this.musics) {
                System.out.println("【" + music.getName() +"】"); }}}@Override
    public void play(a) {
        if(musics.size() == 0) {
            System.out.println("The current playlist is empty, please set the playlist first.");
        } else {
            if(cursor == -10000) {
                cursor = 0;
                System.out.println("Start playing:" + musics.get(0).getName());
            } else {
                if(cursor < musics.size()) {
                    if(cursor == pauseCursor) {
                        System.out.println("Continue playing:" + musics.get(cursor).getName());
                        pauseCursor = -10000;
                    } else {
                        if(cursor < 0) {
                            cursor = musics.size() - 1;
                        }
                        System.out.println("Start playing:"+ musics.get(cursor).getName()); }}else {
                    System.out.println("Playlist songs have been played, start over.");
                    cursor = 0;
                    System.out.println("Start playing:" + musics.get(0).getName()); }}}}@Override
    public void next(a) {
        cursor++;
        play();
    }

    @Override
    public void pre(a) {
        cursor--;
        play();
    }

    @Override
    public void pause(a) {
        pauseCursor = cursor;
        System.out.println("Pause play"); }}Copy the code

Finally, the caller → client interacts with the caller to manipulate different command objects.

public class Client {
    public static void main(String[] args) {
        // Instantiate the playlist
        List<Music> musics = new ArrayList<>();
        musics.add(new Music("Snow White".""));
        musics.add(new Music(The Frog's Wish.""));
        musics.add(new Music("The Donkey and the Horse".""));
        musics.add(new Music("The troubles of the little frog.".""));
        musics.add(new Music("Three-character Sutra".""));

        // Instantiate the receiver
        IPlayer musicPlayer = new MusicPlayer();

        // Instantiate the caller and pass in a concrete command instance
        Invoker invoker = new Invoker();
        invoker.setSetPlayListCommand(new SetPlayListCommand(musicPlayer));
        invoker.setPlayCommand(new PlayCommand(musicPlayer));
        invoker.setNextCommand(new NextCommand(musicPlayer));
        invoker.setPreCommand(new PreCommand(musicPlayer));
        invoker.setPauseCommand(new PauseCommand(musicPlayer));

        // Test call
        invoker.play();
        invoker.setPlayList(null); invoker.setPlayList(musics); invoker.play(); invoker.next(); invoker.pre(); invoker.pre(); invoker.pause(); invoker.play(); invoker.next(); invoker.next(); invoker.next(); invoker.next(); invoker.next(); }}Copy the code

The code runs as follows:

The code is pretty straightforward, and the roles involved are described, so I won’t repeat them:

Abstract command, concrete command, abstract receiver, concrete receiver, caller

Directly bring out UML class diagrams, usage scenarios, and pros and cons

Usage scenarios

  • In programming languages that do not support function passing, the command mode allows functions to be used as objects.
  • Request the caller and receiver to be decouple, do not interact directly, the caller does not need to know who the receiver is and how to operate;
  • Build functions around command dimensions, freely combine related commands, and statistical tracking behavior operations;

Advantages:

  • With looser coupling, the requester does not need to know who the executor is and how the instruction is executed.
  • More dynamic control, request encapsulation, dynamic parameterization, queuing, logging and other operations.
  • Commands can be compounded, that is, a command can be composed of multiple commands, also known as macro commands
  • Better extensibility, because the initiator of the command is decouple from the executor, extending new commands requires only implementing new command objects;
  • It provides a design and implementation scheme for Undo and Redo operations

disadvantages

  • Different receivers need to implement duplicate commands;
  • When the object involved in the command changes, the result may be different.
  • When a command is added, the corresponding receiver must add the command implementation, which will also affect the implementation of the receiver and is not easy to maintain.

That’s all for this section. Thank you