LoginSignup
5
5

More than 5 years have passed since last update.

PHPで使うGoFパターン ひとり Advent Calendar - コマンド

Last updated at Posted at 2012-07-24

コマンドってなに?

要するにコマンド(命令)を統一シグニチャでクラスにまとめて、
一連で実行出来るような仕組みとして実装するパターンです。
身近なところの実装例としては以下

  • undo, redo
  • エディタのキーボードマクロ(場合によってはスクリプト保存付きも可能)
  • キュー管理のバッチジョブコントローラ

コマンドパターンの構造

  • Invoker - コマンドをスタックに保持したり、コマンドを実行したり
  • Receiver - コマンドに操作される対象のクラス。内部に状態を持っていてCommandの操作によって内部の状態が変化したりする
  • Client - Invokerを操作するコントローラ
  • Command - 実コマンド。Receiverを操作することでコマンドを実現。Invokerに利用される
<?php

/* Reciever */
class FileSystem   {
  private $_Path = null;

  public function __construct ( $path ) {
    $this->_Path = $path;
  }

  // コマンドに利用されるAPIだよ
  public function changeDirectory () {
    return `cd $this->_Path`;
  }

  // コマンドに利用されるAPIだよ。
  public function makeDirectory () {
    return `mkdir $this->_Path`;
  }

  // コマンドに利用されるAPIだよ。
  public function removeDirectory () {
    return `rm $this->_Path`;
  }

  // コマンドに利用されるAPIだよ。
  public function createFile () {
    return `touch $this->_Path`;
  }
}
<?php
/* command interface */
interface ICommand {
  public function execute ();
  public function undo ();
}

/* 実コマンド */
class MakeDirectoryCommand implements ICommand {
  private $_FileSystem = null;

  public function __construct ( $fs ) {
    $this->_FileSystem = $fs;
  }

  public function execute () {
    $this->_FileSystem->makeDirectory ();
  }

  public function undo () {  
    $this->_FileSystem->removeDirectory ();
  }
}


class RemoveDirectoryCommand implements ICommand {

  private $_FileSystem = null;
  public function __construct ( $fs ) {
    $this->_FileSystem = $fs;
  }

  public function execute () {
    $this->_FileSystem->removeDirectory ();
  }

  public function undo () {  
    $this->_FileSystem->makeDirectory ();
  }
}
<?php
/* Client */
class ShellScript {
  private $_Queue    = array ();
  private $_Position = 0;

  public function add ( $cmd ) {
    $this->_Queue[] = $cmd;
  }

//  // MEMO: 実行途中にnextしたり、undoしてポジションを戻して
//  //       中途からコマンド上書きしたりも出来るよ
//  public function next () {
//    return ++$this->_Position;
//  }
//  public function undo ( $times = 1 ) {
//    $this->_Queue[$this->_Position]->undo();
//    for ( $i = 0; $times < $i; $i++ ) $this->_Position--;
//  }

  //
  // でも今回はサンプルなのでリニアに実行するだけにするよ
  //
  public function run () {
    foreach ( $this->_Queue as $q ) $q->execute();
  }
}
<?php
/* Clientです。クラスじゃないけど */
$sh = new ShellScript();
$fs = new FileSystem ( '/etc/tmp/sample' );
$sh->add ( new MakeDirectoryCommand ( $fs ) );
$sh->add ( new RemoveDirectoryCommand ( $fs ) );
$sh->run ();
5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5