Command Pattern

Muzi·2023년 7월 1일
0

디자인 패턴

목록 보기
13/14
post-thumbnail

Command Pattern

: 처리하고 싶은 일을 메소드 호출이라는 동적인 처리로 표현하는게 아닌 명령을 나타내는 하나의 객체로 표현

예제

그림을 그리는 프로그램

마우스를 드래그시 빨간색 점으로 된 선이 그려지고
clear 버튼을 클릭시 모든 점이 사라진다
즉, 마우스를 드래그할때마다 이 위치에 점을 그려라느 명령이 클래스의 인스턴스로 생성된다

클래스,인터페이스 목록

  • Command(interface) - 명령을 표현하는 인터페이스
  • MacroCommand - 복수의 명령으르 모은 명령을 표현하는 클래스
  • DrawCommand - 점 그리기 명령을 표현하는 클래스
  • Drawable(interface) - 그리는 대상을 표현하는 인터페이스
  • DrawCanvas - 그리는 대상을 구현하는 클래스
  • Main - 동작 테스트용

MacroCommand - invoker

import java.util.ArrayDeque;
import java.util.Iterator;

public class MacroCommand implements Command {
    // 명령의 집합
    private Stack commands = new Stack();
    // 명령들을 실행
    public void execute() {
        Iterator it = commands.iterator(); 
        while (it.hasNext()) {             
            ((Command)it.next()).execute();
        }                               
    }
    // command 인스턴스를 추가
    public void append(Command cmd) {
        if (cmd != this) {
            commands.push(cmd);
        }
    }
    // 마지막으로 추가된 명령을 삭제
    public void undo() {
        if (!commands.empty()) {
            commands.pop();
        }
    }
    // 전부 삭제
    public void clear() {
        commands.clear();
    }
}
  • 복수의 명령을 모아놨음

command

public interface Command {
    public abstract void execute();
}
  • '무언가'를 실행함

DrawCommand

import command.Command;
import java.awt.Point;

public class DrawCommand implements Command {
    // 그림 그리기 대상
    protected Drawable drawable;
    // 그림 그리기 위치
    private Point position;
    // 생성자
    public DrawCommand(Drawable drawable, Point position) {
        this.drawable = drawable;
        this.position = position;
    }
    // 실행
    public void execute() {                  
        drawable.draw(position.x, position.y); 
    }                                      
}
  • 점을 그리는 명령을 표현한 클래스

Drawable

package drawer;

public interface Drawable {
    public abstract void draw(int x, int y);
}
  • 그리는 대상을 나타냄

DrawCanvas

import command.*;

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

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;
    }
    // 이력 전체를 다시 그리기
    public void rePaint(Graphics g) {
        history.execute();
    }
    // 그림 그리기
    public void draw(int x, int y) {
        Graphics g = getGraphics();
        g.setColor(color);
        g.fillOval(x - radius, y - radius, radius * 2, radius * 2);
    }
}

Main

import command.*;
import drawer.*;

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

public class Main 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 Main(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 Main("Command Pattern Sample");
    }
}

장점

  • 수행하는 객체와 요청하는 객체의 분리
  • 커맨드 단위의 액션
  • 작업 수행 취소/다시 실행을 구현하는데 사용
  • 반복되는 작업을 가진 자식 클래스들 같은 문제 줄임
profile
좋아하는걸 열심히

0개의 댓글