Chapter 22. Command : 명령을 클래스로 만든다
61078 단어 Design PatternDesign Pattern
1. 예제 프로그램 - 간단한 그림 그리기 프로그램
<Command.java>
package ch22.Sample.command;
// ‘명령’을 표현하기 위한 인터페이스
public interface Command {
// 무언가를 실행하는 메소드
// 구체적으로 무슨 일을 하는지는
// Command 인터페이스를 구현한 클래스가 결정한다.
public abstract void execute();
}
<DrawCommand.java>
package ch22.Sample.drawer;
import ch22.Sample.command.Command;
import java.awt.Point;
// ‘그림 그리기 명령’을 표현함
public class DrawCommand implements Command {
// 그림 그리기를 실행할 대상(객체)를 저장함
protected Drawable drawable;
// 그림 그리는 위치
private Point position;
// java.awt.Point 클래스: X좌표와 Y좌표를 갖는 클래스
// 2차원 평면 상의 위치를 나타냄
// 속성으로 x, y를 가진다.
// 생성자
public DrawCommand(Drawable drawable, Point position) {
this.drawable = drawable;
this.position = position;
}
// 실제 그리기를 실행하는 메소드
// drawable 필드의 draw 메소드를 호출함
public void execute() {
drawable.draw(position.x, position.y);
}
}
<MacroCommand.java>
package ch22.Sample.command;
import java.util.Stack;
import java.util.Iterator;
// ‘여러 개의 명령을 한데 모은 명령’을 나타냄
// Composite 패턴이 사용됨
// => 여러 개의 명령을 모은 것(container)이면서,
// 그 자체가 하나의 명령(content)가 된다.
public class MacroCommand implements Command {
// 다수의 Command를 모아둠
// Stack: 나중에 들어간 원소가 먼저 나오는 자료구조체
private Stack commands = new Stack();
// 실행
public void execute() {
// 자신이 가지고 있는 모든 명령의 execute( )을 호출한다(실행한다)
Iterator it = commands.iterator();
while (it.hasNext()) {
((Command) it.next()).execute();
}
// 자신이 가지고 있는 명령이 MacroCommand이면,
// 그 MacroCommand가 가지고 있는 명령들의 execute( )이 차례대로 실행된다.
// (recursive call)
}
// MacroCommand 클래스에
// 새로운 Command(Command 인터페이스를 구현한 클래스의 인스턴스)를
// 추가하는 메소드
public void append(Command cmd) {
// 실수로 자기 자신을 추가하지 않도록 체크함
// 자기 자신이 추가되면, execute( ) 실행 시 무한 루프가 돌게 된다.
if (cmd != this) {
commands.push(cmd); // Stack 클래스의 push( )를 이용함
}
}
// commands의 마지막 명령을 삭제하는 메소드
public void undo() {
if (!commands.empty()) {
commands.pop();
}
}
// commands 의 모든 명령을 삭제하는 메소드
public void clear() {
commands.clear();
}
}
<Drawable.java>
package ch22.Sample.drawer;
// ‘그림 그리기 대상’을 표현함
public interface Drawable {
public abstract void draw(int x, int y);
}
<DrawCanvas.java>
package ch22.Sample.drawer;
import ch22.Sample.command.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
// Drawable 인터페이스를 구현하고, java.awt.Canvas 를 상속함
public class DrawCanvas extends Canvas implements Drawable {
// 그림 그리는 색
private Color color = Color.red;
// 그림 그리기를 할 점의 변경
private int radius = 6;
// 지금까지 실행한 그림 그리기 명령어들의 집합을 가지고 있음
private MacroCommand history;
// 폭, 높이, 그림 그리기 이력(history)를 받아서,
// DrawCanvas 인스턴스를 초기화한다.
public DrawCanvas(int width, int height, MacroCommand history) {
setSize(width, height);
setBackground(Color.white);
this.history = history;
}
// DrawCanvas를 다시 그릴 필요가 생겼을 때
// java.awt 프레임워크로부터 자동으로 호출되는 메소드
// repaint( ) 메소드가 호출되면, 화면이 지워진 후 자동으로 paint( ) 메소드가 실행된다.
public void paint(Graphics g) {
// history가 보관하고 있는 모든 그리기 명령들을 실행한다.
history.execute();
}
// 그리기
public void draw(int x, int y) {
// Graphics 객체를 얻어서,
Graphics g = getGraphics();
// 색깔을 빨간색으로 지정하고
g.setColor(color);
// Graphics 객체의 filloval(x, y, 사각형 가로, 사각형 세로)을
// 이용하여 원을 그린다.
g.fillOval(x - radius, y - radius, radius * 2, radius * 2);
}
}
<Main.java>
package ch22.Sample;
import ch22.Sample.command.*;
import ch22.Sample.drawer.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
// 예제 프로그램을 작동시키는 클래스
public class Main extends JFrame implements ActionListener,
MouseMotionListener, WindowListener {
// DrawCanvas 생성 시에 인자로 넘겨줌
// Main 인스턴스와 DrawCanvas 인스턴스가 history를 공유한다.
private MacroCommand history = new MacroCommand();
// 그림 그리는 영역을 나타냄
private DrawCanvas canvas = new DrawCanvas(400, 400, history);
// javax.swing.JButton 클래스
// 그린 점들을 모두 지우는 버튼
private JButton clearButton = new JButton("clear");
public Main(String title) {
super(title);
// 리스너 등록하기
this.addWindowListener(this);
canvas.addMouseMotionListener(this);
clearButton.addActionListener(this);
// 여러 가지 GUI 부품을 배치함
// Box 객체를 이용함
// Box: BoxLayout 객체를 레이아웃매니저로 사용하는 가벼운 컨테이너
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();
setVisible(true);
}
// clearButton이 눌러졌을 때 호출되는 메소드
public void actionPerformed(ActionEvent e) {
if (e.getSource() == clearButton) {
history.clear(); // history에 보관되어 있던 모든 명령을 지우고
canvas.repaint(); // 캔버스의 repaint( )가 호출된다.
}
}
// MouseMotionListener
public void mouseMoved(MouseEvent e) {
}
// 사용자가 마우스를 drag 하면 이 메소드가 호출된다.
public void mouseDragged(MouseEvent e) {
// 그리기 명령을 나타내는 DrawCommand 객체를 생성한 후,
Command cmd = new DrawCommand(canvas, e.getPoint()); // e.getPoint( ) : 마우스 이벤트가 발생한 위치를 얻음
history.append(cmd); // 이를 history에 추가하고,
cmd.execute(); // 지정 위치에 빨간 점을 그린다.
}
// WindowListener
// 창의 오른 쪽 위 아이콘 중에 X 사각형을 눌렀을 때 호출되는 메소드
public void windowClosing(WindowEvent e) {
System.exit(0);
}
// WindowListener 인터페이스에 선언되어 있는 나머지 메소드들
// 구현할 필요가 없으므로, 빈 문장의 메소드로 구현되어 있다.
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");
}
}
2. 연습문제 3번 - 어댑터 사용
<Command.java>
package ch22.Sample.command;
// ‘명령’을 표현하기 위한 인터페이스
public interface Command {
// 무언가를 실행하는 메소드
// 구체적으로 무슨 일을 하는지는
// Command 인터페이스를 구현한 클래스가 결정한다.
public abstract void execute();
}
<DrawCommand.java>
package ch22.A3.drawer;
import ch22.A3.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);
}
}
<MacroCommand.java>
package ch22.A3.command;
import java.util.Stack;
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();
}
}
// 추가
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.java>
package ch22.A3.drawer;
public interface Drawable {
public abstract void draw(int x, int y);
}
<DrawCanvas.java>
package ch22.A3.drawer;
import ch22.A3.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 paint(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.java>
package ch22.A3;
import ch22.A3.command.*;
import ch22.A3.drawer.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Main extends JFrame implements ActionListener {
// 그리기 이력
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(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
canvas.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
Command cmd = new DrawCommand(canvas, e.getPoint());
history.append(cmd);
cmd.execute();
}
});
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();
setVisible(true);
}
// ActionListener용
public void actionPerformed(ActionEvent e) {
if (e.getSource() == clearButton) {
history.clear();
canvas.repaint();
}
}
public static void main(String[] args) {
new Main("Command Pattern Sample");
}
}
Author And Source
이 문제에 관하여(Chapter 22. Command : 명령을 클래스로 만든다), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@rosesua318/Chapter-22.-Command-명령을-클래스로-만든다저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)