Skeleton of GOF's Design Pattern


COMMANDの骸骨

COMMAND

このパターンは、要求を出すオブジェクトと処理をするオブジェクトを分離します

COMMAND パターンは、、InvokerCommand と Receiver の三つのクラスで構成されています。Invoker はイベント(メソッド呼び出し)を受けると、イベントに対応する処理を行う Command を生成し、しかるべき手順でを発火させる役割を担います。Command はイベントに応じた処理を手順を記述したものです。スクリプトのようなものと捉えるとわかりやすいと思います。Receiver は、その処理を行う実体です。実際にはOSやミドルウェアが用意するAPIや、ドライバなどがそれにあたると思います。

このパターンは、イベントに対する処理の流れが Command にカプセル化されますので、イベントに対応した手順が非常に分かりやすくなるのが特徴です。組み込みシステムでは非常に有用なパターンです。

具体例を知りたい方は、COMMAND でMIDIプレイヤーを作ってみよう』 を参照してください。


■ 『COMMANDの骸骨』の構造


■ 『COMMANDの骸骨』の協調関係


■ 『COMMANDの骸骨』 プログラム・コード

□ Java2版
// Copyright(C) 2000-2003 Yoshinori Oota All rights reserved.

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

public class CommandSample { 
    static public void main(String[] args) { 
        Invoker invoker = new Invoker();

        invoker.Store(new PrintCommand("Hello Command Pattern."));
        invoker.Store(new DialogCommand("This is Command Pattern."));

        invoker.Execute();
    } 
}

class Invoker { 
    private LinkedList _commandQueue = new LinkedList();
    public void Store(Command command) { 
        _commandQueue.add(command); 
    }
    public void Execute() { 
        while (_commandQueue.size() != 0) {
            Command command = (Command)_commandQueue.removeFirst();
            command.Execute();
        }
    }
}

abstract class Command { 
    abstract public void Execute();
}

class PrintCommand extends Command { 
    private String _value = null;
    public PrintCommand(String val) {
        _value = val;
    }
    public void Execute() { 
        System.out.println(_value);  // System が Receiver になる。
    }
}

class DialogCommand extends Command implements ActionListener { 
    private String _value = null;
    private Frame  _frame = new Frame("Command Sample"); // Frame が Reciver.
    public DialogCommand(String val) {
        _value = val;
    }
    public void Execute() {
        _frame.add("Center", new Label(_value, Label.CENTER));
        Button ok = new Button("OK");
        ok.addActionListener(this);
        _frame.add("South", ok);
        _frame.setSize(200, 100);
        _frame.show();
    }
    public void actionPerformed(ActionEvent event) {
        _frame.dispose();
        System.exit(0);
    }
}

○ C++版
// Copyright(C) 2003 Yoshinori Oota All rights reserved.

#include <windows.h>
#include <list>
#include <iostream>
using namespace std;

class Command {
public:
    Command();
    virtual ~Command();
    virtual void Execute() = 0;
};

class PrintCommand : public Command {
public:
    PrintCommand(const string& str);
    virtual ~PrintCommand();
    virtual void Execute();
private:
    string value_;
};

class DialogCommand : public Command {
public:
    DialogCommand(const string& str);
    virtual ~DialogCommand();
    virtual void Execute();
private:
    string value_;
};

class Invoker {
public:
    Invoker();
    ~Invoker();
     void Store(Command* cmd);
     void Execute();
private:
    list<Command*> commandQueue_;
};


Command::Command() { }
Command::~Command() { }

PrintCommand::PrintCommand(const string& str) : value_(str) { }
PrintCommand::~PrintCommand() { }
void PrintCommand::Execute() {
    cout << value_ << endl;   // iostream がReceiver
}

DialogCommand::DialogCommand(const string& str) : value_(str) { }
DialogCommand::~DialogCommand() { }
void DialogCommand::Execute() {
    // win32 が Receiver.
    MessageBox(0, value_.c_str(), "Command Sample", MB_OK|MB_SETFOREGROUND);
}

Invoker::Invoker() { }
Invoker::~Invoker() {
    list<Command*>::iterator it = commandQueue_.begin();
    while (it != commandQueue_.end()) {
        delete (*it);
        ++it; 
    }
}
void Invoker::Store(Command* cmd) {
    commandQueue_.push_back(cmd);
}
void Invoker::Execute() {
    while (!commandQueue_.empty()) {
        Command* command = commandQueue_.front();
        commandQueue_.pop_front();
        command->Execute();
        delete command; 
    }
}


int main() {
    Invoker* invoker = new Invoker();
    invoker->Store(new PrintCommand("Hello Command Pattern"));
    invoker->Store(new DialogCommand("This is Command Pattern"));
    invoker->Execute();
    delete invoker;
    return 0;
}

○ C版
/* Copyright(C) 2009 Yoshinori Oota All rights reserved. */
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

enum COMMAND_TYPE { PRINT ,DIALOG };

/* Command Interface */
struct Command {
    char* value_;
    void (*Execute)(struct Command* pthis);
};
struct Command* New_Command (enum COMMAND_TYPE type ,char* str);
void Delete_Command(struct Command* command);
void Command_Execute_Print(struct Command* pthis);
void Command_Execute_Dialog(struct Command* pthis);

/* Command Queue Interface */
struct CommandQueue {
    struct Command* cmd_;
    struct CommandQueue* next_;
};
struct CommandQueue* New_CommandQueue(struct Command* command);
void Delete_CommandQueue(struct CommandQueue* queue);


/* Command Class Implementation */
struct Command* New_Command(enum COMMAND_TYPE type ,char* str) {
    struct Command* command = NULL;
    char* value = NULL;

    command = (struct Command*)malloc(sizeof(struct Command));
    value = (char*)malloc(strlen(str)+1);
    strcpy(value, str);
    command->value_ = value;
    switch (type) {
    case PRINT:
        command->Execute = &Command_Execute_Print;
        break;
    case DIALOG:
        command->Execute = &Command_Execute_Dialog;
        break;
    }
    return command;
}

void Delete_Command(struct Command* command) {
    if (command == NULL) {
        return;
    }
    free(command->value_);
    command->value_ = NULL;
    free(command);
    command = NULL;
    return;
}

void Command_Execute_Print(struct Command* pthis) {
    printf("%s\n" ,pthis->value_);
    return;
}

void Command_Execute_Dialog(struct Command* pthis) {
    MessageBox(0 ,pthis->value_ ,"Command Sample" ,MB_OK|MB_SETFOREGROUND);
    return;
}


/* CommandQueue Implementation */
struct CommandQueue* New_CommandQueue(struct Command* cmd) {
    struct CommandQueue* queue = NULL;
    queue = (struct CommandQueue*)malloc(sizeof(struct CommandQueue));
    queue->command_ = cmd;
    queue->next_ = NULL;
    return queue;
}

void Delete_CommandQueue(struct CommandQueue* queue) {
    if (queue == NULL) {
        return;
    }
    free(queue);
    queue = NULL;
    return;
}


/* Invoker */
struct CommandQueue* gQueueTop  = NULL;
struct CommandQueue* gQueueLast = NULL;

void Invoker_Store(struct Command* cmd) {
    struct CommandQueue* queue = NULL;

    if (gQueueTop == NULL) {
        gQueueTop = New_CommandQueue(cmd);
        gQueueLast = gQueueTop;
    } else {
        gQueueTop = New_CommandQueue(cmd);
        gQueueLast->next_ = queue;
        gQueueLast = queue;
    }
    return;
}

void Invoker_Execute() {
    struct CommandQueue* cur = NULL;
    struct Command* command  = NULL;

    while (gQueueTop != NULL) {
        tmp = gQueueTop->next_;
        command = gQueueTop->command_;
        command->Execute(command);
        Delete_Command(command);
        Delete_CommandQueue(gQueueTop);
        gQueueTop = tmp;
    }
    gQueueLast = NULL;
    return;
}

void Invoker_Clean() {
    struct CommandQueue* cur = NULL;
    struct CommandQueue* tmp = NULL;

    while (gQueueTop != NULL) {
        tmp = gQueueTop->next_;
        Delete_Command(gQueueTop->command_);
        Delete_CommandQueue(gQueueTop);
        gQueueTop = tmp;
    }
    gQueueLast = NULL;
    return;
}

int main() {
    Invoker_Store(New_Command(PRINT ,"Hello Command Pattern"));
    Invoker_Store(New_Command(DIALOG ,"This is Command Pattern"));
    Invoker_Execute();
    Invoker_Clean();
    return 0;
}


改訂履歴

2005.2.25 説明文が意味不明なのを修正さらにデザインパターンの塗り薬へのリンクを追加
  2009.2.22 C言語版を追加
     

ご意見、ご感想はこちらまで。

Copyright(C) 2000-2009 Yoshinori Oota All rights reserved.

本ホームページのリンクは自由です。複製、転載される場合は、必ず著者までご連絡をください。