設計模式學習筆記——命令(Command)模式

設計模式學習筆記——命令(Command)模式

@(設計模式)[設計模式, 命令模式, command]

基本介紹

將一個請求封裝爲一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支持可撤消的操作。

命令案例

類圖

命令案例類圖

實現代碼

Command接口

package com.pc.command.example.command;

/**
 * 命令接口
 * Created by Switch on 2017/3/31.
 */
public interface Command {
    /**
     * 執行
     */
    void execute();
}

MacroCommand類

package com.pc.command.example.command;

import java.util.Iterator;
import java.util.Stack;

/**
 * 大量命令類
 * Created by Switch on 2017/3/31.
 */
public class MacroCommand implements Command {
    /**
     * 命令的集合
     */
    private Stack<Command> commands = new Stack<>();

    @Override
    public void execute() {
        Iterator<Command> it = commands.iterator();
        while (it.hasNext()) {
            it.next().execute();
        }
    }

    /**
     * 添加命令
     *
     * @param cmd 命令
     */
    public void append(Command cmd) {
        if (cmd != this) {
            commands.push(cmd);
        }
    }

    /**
     * 刪除最後一條命令
     */
    public void undo() {
        if (!commands.empty()) {
            commands.pop();
        }
    }

    /**
     * 刪除所有命令
     */
    public void clear() {
        commands.clear();
    }
}

Drawable接口

package com.pc.command.example.drawer;

/**
 * 繪圖接口
 */
public interface Drawable {
    /**
     * 繪製
     *
     * @param x x座標
     * @param y y座標
     */
    void draw(int x, int y);
}

DrawCommand類

package com.pc.command.example.drawer;

import com.pc.command.example.command.Command;

import java.awt.*;

/**
 * 繪圖命令類
 */
public class DrawCommand implements Command {
    /**
     * 繪製對象
     */
    protected Drawable drawable;
    /**
     * 繪製位置
     */
    private Point position;

    public DrawCommand(Drawable drawable, Point position) {
        this.drawable = drawable;
        this.position = position;
    }

    @Override
    public void execute() {
        drawable.draw(position.x, position.y);
    }
}

DrawCanvas類

package com.pc.command.example.drawer;

import com.pc.command.example.command.MacroCommand;

import java.awt.*;

/**
 * 繪製面板類
 */
public class DrawCanvas extends Canvas implements Drawable {
    /**
     * 顏色
     */
    private Color color = Color.red;
    /**
     * 要繪製的圓點的半徑
     */
    private int radius = 6;
    /**
     * 命令的歷史記錄
     */
    private MacroCommand history;

    public DrawCanvas(int width, int height, MacroCommand history) {
        setSize(width, height);
        setBackground(Color.white);
        this.history = history;
    }

    @Override
    public void paint(Graphics g) {
        history.execute();
    }

    @Override
    public void draw(int x, int y) {
        Graphics g = getGraphics();
        g.setColor(color);
        g.fillOval(x - radius, y - radius, radius * 2, radius * 2);
    }
}

測試類

package com.pc.command.example.test;

import com.pc.command.example.command.Command;
import com.pc.command.example.command.MacroCommand;
import com.pc.command.example.drawer.DrawCanvas;
import com.pc.command.example.drawer.DrawCommand;

import javax.swing.*;
import java.awt.event.*;


/**
 * MacroCommand Tester.
 *
 * @author Switch
 * @version 1.0
 */
public class CommandTest extends JFrame implements ActionListener, MouseMotionListener, WindowListener {
    // 繪製的歷史記錄
    private MacroCommand history = new MacroCommand();
    // 繪製區域
    private DrawCanvas canvas = new DrawCanvas(400, 400, history);
    // 刪除按鈕
    private JButton clearButton = new JButton("clear");

    // 構造函數
    public CommandTest(String title) {
        super(title);

        this.addWindowListener(this);
        canvas.addMouseMotionListener(this);
        clearButton.addActionListener(this);

        Box buttonBox = new Box(BoxLayout.X_AXIS);
        buttonBox.add(clearButton);
        Box mainBox = new Box(BoxLayout.Y_AXIS);
        mainBox.add(buttonBox);
        mainBox.add(canvas);
        getContentPane().add(mainBox);

        pack();
        show();
    }

    // ActionListener接口中的方法
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == clearButton) {
            history.clear();
            canvas.repaint();
        }
    }

    // MouseMotionListener接口中的方法
    public void mouseMoved(MouseEvent e) {
    }

    public void mouseDragged(MouseEvent e) {
        Command cmd = new DrawCommand(canvas, e.getPoint());
        history.append(cmd);
        cmd.execute();
    }

    // WindowListener接口中的方法
    public void windowClosing(WindowEvent e) {
        System.exit(0);
    }

    public void windowActivated(WindowEvent e) {
    }

    public void windowClosed(WindowEvent e) {
    }

    public void windowDeactivated(WindowEvent e) {
    }

    public void windowDeiconified(WindowEvent e) {
    }

    public void windowIconified(WindowEvent e) {
    }

    public void windowOpened(WindowEvent e) {
    }

    public static void main(String[] args) {
        new CommandTest("Command Pattern Sample");
    }
}

運行結果

這裏寫圖片描述

命令模式中的角色

Command(命令)

Command角色負責定義命令的接口(API)。在案例中,由Command接口扮演此角色。

ConcreteCommand(具體的命令)

ConcreteCommand角色負責實現在Command角色中定義的接口(API)。在案例中,由MacroCommand類和DrawCommand類扮演此角色。

Receiver(接收者)

Receiver角色是Command角色執行命令時的對象,也可以稱其爲命令接收者。在案例中,由DrawCanvas類接收DrawCanvas類和DrawCommand類扮演此角色。

Client(請求者)

Client角色負責生成ConcreteCommand角色並分配Receiver角色。在案例中,由測試類扮演此角色。在響應鼠標拖拽事件時,它生成了DrawComrnand類的實例,並將扮演Receiver角色的DrawCanvas類的實例傳遞給了DrawCommand 類的構造函數。

Invoker(發動者)

Invoker角色是開始執行命令的角色,它會調用在Command角色中定義的接口(API)。在案例中,由測試和DrawCanvas類扮演此角色。這兩個類都調用了Command接口中的execute方法。測試類同時扮演了Client角色和Invoker角色。

類圖

命令模式類圖

時序圖

命令模式時序圖

GitHub:DesignPatternStudy

——————參考《圖解設計模式》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章