倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

「GoF デザインパターン」アノテーション (14) : Command パターン

今回は Command パターン一覧)。

Command パターンの登場人物

  • @Command → 型
    • @Execute → メソッド
  • @ConcreteCommand → 具象クラス
    • commandType : Class<?>
    • @ReceiverInstance → フィールド
  • @Receiver → 型
    • concreteCommandType : Class<?>
  • @Invoker → 型
    • commandType : Class<?>
  • @Client → 具象クラス
    • commandType : Class<?>

アノテーション定義


上記の定義の具体的な Java コード。

package org.waman.tools.design.gof.behavioral;

import java.lang.annotation.*;

public final class CommandPattern {
    
    private CommandPattern(){}

    @Target(ElementType.TYPE)
    public static @interface Command{

        @Inherited @Target(ElementType.METHOD)
        public static @interface Execute{}
    }

    @Target(ElementType.TYPE)
    public static @interface ConcreteCommand{

        Class<?> commandType() default Void.class;

        @Inherited @Target(ElementType.FIELD)
        public static @interface ReceiverInstance{}
    }

    @Target(ElementType.TYPE)
    public static @interface Receiver{
        Class<?> concreteCommandType() default Void.class;
    }

    @Target(ElementType.TYPE)
    public static @interface Invoker{
        Class<?> commandType() default Void.class;
    }

    @Target(ElementType.TYPE)
    public static @interface Client{
        Class<?> commandType() default Void.class;
    }
}

サンプルコード in 『Java 言語で学ぶデザインパターン入門』


Command.java

@Command 役のインターフェース。

import org.waman.tools.design.gof.behavioral.CommandPattern;
import org.waman.tools.design.gof.behavioral.CommandPattern.Command.Execute;

@CommandPattern.Command
public interface Command {
    @Execute public abstract void execute();
}

MacroCommand.java

@ConcreteCommand 役のクラス、その1。

import org.waman.tools.design.gof.behavioral.CommandPattern;

@CommandPattern.ConcreteCommand(commandType = Command.class)
public class MacroCommand implements Command {
    ...
    @Override public void execute() {...}
}

DrawCommand.java

import java.awt.Point;
import org.waman.tools.design.gof.behavioral.CommandPattern;
import org.waman.tools.design.gof.behavioral.CommandPattern.ConcreteCommand.ReceiverInstance;

@CommandPattern.ConcreteCommand(commandType = Command.class)
public class DrawCommand implements Command {
    
    @ReceiverInstance protected Drawable drawable;
    private Point position;
    
    ...
    
    @Override public void execute() {
        drawable.draw(position.x, position.y);
    }
}

Drawable.java

@Receiver 役のクラス。 DrawCommand クラスにインスタンスを保持され、そこから処理を受け取ります。

import org.waman.tools.design.gof.behavioral.CommandPattern;

@CommandPattern.Receiver(concreteCommandType = DrawCommand.class)
public interface Drawable {
    public abstract void draw(int x, int y);
}

DrawCanvas.java

Drawable インターフェースの実装クラス。 内部で Command#execute() を呼び出しているので、@Invoker 役となります。

import java.awt.*;
import org.waman.tools.design.gof.behavioral.CommandPattern;

@CommandPattern.Invoker(commandType = Command.class)
public class DrawCanvas extends Canvas implements Drawable {
    
    private static final long serialVersionUID = -5768616080475206281L;
    ...
    
    public DrawCanvas(int width, int height, MacroCommand history) {...}
    
    @Override public void paint(Graphics g) {
        history.execute();
    }
    
    @Override public void draw(int x, int y) {...}
}

Main.java

@Invoker 役であり、@Client 役でもあるクラス。

@CommandPattern.Invoker(commandType = Command.class)
@CommandPattern.Client(commandType = Command.class)
public class Main extends JFrame 
        implements ActionListener, MouseMotionListener, WindowListener {
    ...

    public Main(String title) {...}

    ...

    @Override public void actionPerformed(ActionEvent e) {
        if (e.getSource() == clearButton) {
            history.clear();
            canvas.repaint();
        }
    }
    
    @Override
    public void mouseDragged(MouseEvent e) {
        Command cmd = new DrawCommand(canvas, e.getPoint());
        history.append(cmd);
        cmd.execute();
    }

    @Override
    public void windowClosing(WindowEvent e) {
        System.exit(0);
    }

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

増補改訂版Java言語で学ぶデザインパターン入門 オブジェクト指向における再利用のためのデザインパターン Code Complete第2版〈上〉―完全なプログラミングを目指して Code Complete第2版〈下〉―完全なプログラミングを目指して