Հրաման (նախագծման ձևանմուշ)

Անվան այլ կիրառումների համար տե՛ս՝ Հրաման (այլ կիրառումներ)

Հրաման (անգլ.՝ Command pattern), վարքագծային նախագծման ձևանմուշ, որն օգտագործվում է օբյեկտ կողմնորոշված ծրարգավորման մեջ գործողությունը ներկայացնելու համար։ Հրամանի օբյեկտն իր մեջ պարունակում է գործողությունն իր պարամետրերով։

Հրաման
ՏեսակՎարքագծային
Նշանակությունօբյեկտի տեսքով հրամանները մշակելու համար
Նկարագրությունը ԳօՖի
"Design Patterns" գրքում
Այո

Ընդհանուր հասկացողություններ խմբագրել

  • Client - հայցող
  • Instance - նմուշ
  • Implementation - իրականացում
  • Product - արգասիք

Նպատակ խմբագրել

Սրուկտուրայի ստեղծում, որտեղ ուղարկող և ստացող դասերը ուղիղ գծով միմյանց հետ կապված չեն։ Կազմակերպում է դասի հետադարձ կանչ, որն ներառում է ուղարկող դաս։

Նկարագրություն խմբագրել

Վարքագծային այս ձևանմուշը հայտնի է նաև Action (գործողություն) անվանումով։

Ապահովում է հրամանի մշակումը օբյեկտի տեսքով, որը թույլ է տալիս հիշել այն և որպես պարամետր ներկայացնել դասերի մեթոդներին, ինչպես նաև վերադարձնել նրա արժեքը։

Օրինակ տպիչի գրադարանը կարող է ունենա PrintJob դաս։ Դրա համար կարելի է ստեղծել PrintJob օբյեկտ, դնել անհրաժեշտ պարամետրերը և կանչել մեթոդը, որն անմիջականորեն խնդիրը կուղարկի տպման։

Օրինակներ խմբագրել

С++ խմբագրել

#include <iostream>
#include <vector>
#include <string>
using namespace std;

class Document
{
   vector<string> data; 
public:
   void Insert( int line, const string & str )
   {
      if ( line <= data.size() )
         data.insert( data.begin() + line, str ); 
      else
         cout << "Error!" << endl; 
   }

   void Remove( int line )
   {
      if( !( line>data.size() ) )
         data.erase( data.begin() + line ); 
      else
         cout << "Error!" << endl; 
   }

   string & operator [] ( int x )
   {
      return data[x]; 
   }

   void Show()
   {
      for( int i = 0; i<data.size(); ++i )
      {
         cout << i + 1 << ". " << data[i] << endl; 
      }
   }
};

class Command
{
protected:
   Document * doc; 
public:
   virtual void Execute() = 0; 
   virtual void unExecute() = 0;

   void setDocument( Document * _doc )
   {
      doc = _doc; 
   }
};

class InsertCommand : public Command
{
   int line; 
   string str; 
public:
   InsertCommand( int _line, const string & _str ): line( _line ), str( _str ) {}

   void Execute()
   {
      doc->Insert( line, str ); 
   }

   void unExecute()
   {
      doc->Remove( line ); 
   }
};

class Receiver
{
   vector<Command*> DoneCommands; 
   Document doc; 
   Command* command; 
public:
   void Insert( int line, string str )
   {
      command = new InsertCommand( line, str ); 
      command->setDocument( &doc ); 
      command->Execute(); 
      DoneCommands.push_back( command ); 
   }

   void Undo()
   {
      if( DoneCommands.size() == 0 )
      {
         cout << "There is nothing to undo!" << endl; 
      }
      else
      {
         command = DoneCommands.back(); 
         DoneCommands.pop_back(); 
         command->unExecute();
         // Don't forget to delete command!!!
         delete command;
      }
   }

   void Show()     
   {
      doc.Show(); 
   }
};

int main()
{
   char s = '1'; 
   int line, line_b; 
   string str; 
   Receiver res; 
   while( s!= 'e' )
   {
      cout << "What to do: \n1.Add a line\n2.Undo last command" << endl; 
      cin >> s; 
      switch( s )
      {
      case '1':
         cout << "What line to insert: "; 
         cin >> line; 
         --line; 
         cout << "What to insert: "; 
         cin >> str; 
         res.Insert( line, str ); 
         break; 
      case '2':
         res.Undo(); 
         break; 
      }
      cout << "$$$DOCUMENT$$$" << endl; 
      res.Show(); 
      cout << "$$$DOCUMENT$$$" << endl; 
   }
}

С# խմբագրել

using System;
using System.Collections.Generic;

namespace Command
{

  class MainApp
  {
    static void Main()
    {
      // Создаем пользователя.
      User user = new User();

      // Пусть он что-нибудь сделает.
      user.Compute('+', 100);
      user.Compute('-', 50);
      user.Compute('*', 10);
      user.Compute('/', 2);

      // Отменяем 4 команды
      user.Undo(4);

      // Вернём 3 отменённые команды.
      user.Redo(3);

      // Ждем ввода пользователя и завершаемся.
      Console.Read();
    }
  }

  // "Command" : абстрактная Команда

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

  // "ConcreteCommand" : конкретная команда

  class CalculatorCommand : Command
  {
    char @operator;
    int operand;
    Calculator calculator;

    // Constructor
    public CalculatorCommand(Calculator calculator,
      char @operator, int operand)
    {
      this.calculator = calculator;
      this.@operator = @operator;
      this.operand = operand;
    }

    public char Operator
    {
      set{ @operator = value; }
    }

    public int Operand
    {
      set{ operand = value; }
    }

    public override void Execute()
    {
      calculator.Operation(@operator, operand);
    }

    public override void UnExecute()
    {
      calculator.Operation(Undo(@operator), operand);
    }

    // Private helper function : приватные вспомогательные функции
    private char Undo(char @operator)
    {
      char undo;
      switch(@operator)
      {
        case '+': undo = '-'; break;
        case '-': undo = '+'; break;
        case '*': undo = '/'; break;
        case '/': undo = '*'; break;
        default : undo = ' '; break;
      }
      return undo;
    }
  }

  // "Receiver" : получатель

  class Calculator
  {
    private int curr = 0;

    public void Operation(char @operator, int operand)
    {
      switch(@operator)
      {
        case '+': curr += operand; break;
        case '-': curr -= operand; break;
        case '*': curr *= operand; break;
        case '/': curr /= operand; break;
      }
      Console.WriteLine(
        "Current value = {0,3} (following {1} {2})",
        curr, @operator, operand);
    }
  }

  // "Invoker" : вызывающий

  class User
  {
    // Initializers
    private Calculator _calculator = new Calculator();
    private List<Command> _commands = new List<Command>();

    private int _current = 0;

    public void Redo(int levels)
    {
      Console.WriteLine("\n---- Redo {0} levels ", levels);

      // Делаем возврат операций
      for (int i = 0; i < levels; i++)
        if (_current < _commands.Count)
          _commands[_current++].Execute();
    }

    public void Undo(int levels)
    {
      Console.WriteLine("\n---- Undo {0} levels ", levels);

      // Делаем отмену операций
      for (int i = 0; i < levels; i++)
        if (_current > 0)
          _commands[--_current].UnExecute();
    }

    public void Compute(char @operator, int operand)
    {

      // Создаем команду операции и выполняем её
      Command command = new CalculatorCommand(
        _calculator, @operator, operand);
      command.Execute();

	if (_current < _commands.Count)
	{
	    // если "внутри undo" мы запускаем новую операцию, 
	    // надо обрубать список команд, следующих после текущей, 
	    // иначе undo/redo будут некорректны
		_commands.RemoveRange(_current, _commands.Count - _current);
	}

      // Добавляем операцию к списку отмены
      _commands.Add(command);
      _current++;
    }
  }
}

Java խմբագրել

/*the Invoker class*/

public class Switch {
    private Command flipUpCommand;
    private Command flipDownCommand;

    public Switch(Command flipUpCommand,Command flipDownCommand){
         this.flipUpCommand=flipUpCommand;
         this.flipDownCommand=flipDownCommand;
    }

    public void flipUp(){
         flipUpCommand.execute();
    }
    
    public void flipDown(){
         flipDownCommand.execute();
    }
}

/*Receiver class*/

public class Light{
     public Light(){  }
   
     public void turnOn(){
        System.out.println("The light is on");
     }

     public void turnOff(){
        System.out.println("The light is off");
     }
}

/*the Command interface*/

public interface Command{
    void execute();
}

/*the Command for turning on the light*/

public class TurnOnLightCommand implements Command{
   private Light theLight;

   public TurnOnLightCommand(Light light){
        this.theLight=light;
       }

   public void execute(){
      theLight.turnOn();
   }
}

/*the Command for turning off the light*/

public class TurnOffLightCommand implements Command{
   private Light theLight;

   public TurnOffLightCommand(Light light){
        this.theLight=light;
       }

   public void execute(){
      theLight.turnOff();
   }
}

/*The test class*/
public class TestCommand{
   public static void main(String[] args){
       Light l=new Light();
       Command switchUp=new TurnOnLightCommand(l);
       Command switchDown=new TurnOffLightCommand(l);

       Switch s=new Switch(switchUp,switchDown);
       
       s.flipUp();
       s.flipDown();
   }
}
Այս հոդվածի կամ նրա բաժնի որոշակի հատվածի սկզբնական կամ ներկայիս տարբերակը վերցված է Քրիեյթիվ Քոմմոնս Նշում–Համանման տարածում 3.0 (Creative Commons BY-SA 3.0) ազատ թույլատրագրով թողարկված Հայկական սովետական հանրագիտարանից  (հ․ 6, էջ 619