Full implementation of redo (redo) and undo (undo)

Source: Internet
Author: User

Undo-redo needs memo mode and command mode for support, before having learned some basic knowledge of command mode and memento mode. Here to combine two modes to achieve a Undo-redo operation module, to consolidate the knowledge learned.

System diagram:

The command distribution controller has four main tasks:
1. System initialization, load the system configuration parameters and cache the data, these application-level configuration parameters can use the serialization mechanism, the data cache without having to read the file every time to speed up access efficiency.
2. Based on the front-end request, collect parameters to generate a request.
3. Map the request to the command module for the specific business logic.
4. Perform the operation and return the results to the front-end view.

The business logic layer can get execution parameters based on the incoming context object, and after execution, the execution results can be returned to the previous layer through the context object.

The implementation of the command distribution controller:

Class Controller{private function __construct () {}static function run () {$instance = new Controller (); $instance->init (); $instance->handlerequest ();} function init () {$application = \base\applicationhelper::instance (); $application->system_init ();} function HandleRequest () {$request  = new \controller\request (); $cmd _r = new \command\commandresolver (); $cmd = $cmd _ R->get_command ($request); $cmd->execute ($request);}}
By declaring the constructor as private,controller as a single case.

For an interpreted language like PHP, to implement the Undeo/redo mechanism, a cache mechanism (session) must be used to save the history of command execution. The session module here is primarily responsible for maintaining a command history, which is implemented as follows:

Namespace base;require_once (' session_registry.php '); class Sessionmementotaker extends Sessionregistry{const COMMAND _count = 5;private $persent = 0;private $cmd _stack = array (); static public Function instance () {return parent::instance ();} Public Function Push_command (command $cmd) {$this->cmd_stack = self::instance ()->get (' Cmd_stack '); if (!empty ($ This->cmd_stack) {if (count ($this->cmd_stack) >self::command_count) {array_shift ($this->cmd_stack); Reset ($this->cmd_stack);}} Array_push ($this->cmd_stack, $cmd); $this->persent = count ($this->cmd_stack) + 1;self::instance ()->set (' Cmd_stack ', $this->cmd_stack), Self::instance ()->set (' Cmd_persent ', $this->persent);} Public Function Get_undo_command () {$this->persent = self::instance ()->get (' cmd_persent '); $this->cmd_stack = Self::instance ()->get (' Cmd_stack '); if (!empty ($this->cmd_stack) && $this->persent > 0) {$ Command = $this->cmd_stack[--$this->persent];self::instance ()->set (' CMd_persent ', $this->persent); return $command;} return null;} Public Function Get_redo_command () {$this->persent = self::instance ()->get (' cmd_persent '); $this->cmd_stack = Self::instance ()->get (' Cmd_stack '); if (!empty ($this->cmd_stack) && $this->persent < count ($ This->cmd_stack) {$command = $this->cmd_stack[$this->persent++];self::instance ()->set (' cmd_persent '), $this->persent); return $command;} return null;}}

The implementation of Sessionmementotaker is based on a previously implemented session (registry mode). Depending on the session ID stored in the cookie, the different object data can be recovered, and the same user may request access to the same object data multiple times. Sessionmementotaker provides an additional three interfaces, Push_command operations to add commands to the list of history commands. The history command list has a maximum length of 5, with more than 5 removed from the first command. In addition, Push_command is equivalent to adding a new command to move the command pointer (persent) to the latest position. Discard the previous state. Get_undo_command gets the last executed history command and updates the pointer, Get_redo_command the same.
History command list: Command1---command2---command3---* asterisk indicates persent, pointing to the latest command to execute.
One undo operation: Command1---Command2-*--command3 the pointer moves backwards after---rollback.
One undo operation: Command1--*command2----COMMAND3 The pointer moves backwards after---rollback.
One redo operation: Command1---Command2-*--command3 the persent pointer moves forward after the redo---.
PUSH_COMMAND:COMMAND1---command2---command3---command4---* persent update to the front end

A single Command object is seen here as a primitive (originator). Proactively create a memo (memento) as needed to save its internal state at this point and put the command object in the history command record list.

Command base class implementation:

Namespace Woo\command;require_once ('.. /memento/state.php '); require_once ('. /memento/memento.php '); abstract class Command {protected $state; final function __construct () {$this->state = new \woo \memento\state ();} function execute (\woo\controller\request $request) {$this->state->set (' Request ', $request); $this->do_ Execute ($request);} Abstract function Do_execute (\woo\controller\request $request); function Do_unexecute (\woo\controller\request $ Request) {}public function get_state () {return $this->state;} Public Function set_state (state $state) {$this->state = $state;} Public Function Get_request () {if (Isset ($this->state)) {return $this->state->get (' request ');} return null;} Public Function Set_request (\woo\controller\request $request) {if (Isset ($this->state)) {return $this->state- >set (' request ', $request);}} Public Function Create_memento () {\woo\base\sessionmementotaker::p ush_command ($this); $mem = new \woo\memento\memento        (); $mem->set_state ($this->state); ReTurn $mem;} Public function Set_memento (Memento $mem) {$this->state = $mem->get_state ();}}

The command task saves the parameters of the request command at the beginning of execution, and other necessary parameters can be saved during the execution of the command. Because some commands do not support undo operations, an empty Unexecute is implemented in the parent class.

Object that holds the state of the command:

Class State{private $values = Array (), function __construct () {}public function set ($key, $value) {$this->values[$key] = $value;} Public function Get ($key) {if (Isset ($this->values[$key]) {return $this->values[$key];} return null;}}

A command to copy files that supports Undo-redo:

Namespace woo\command;require_once (' request.php '); require_once (' command.php '); require_once ('.. /base/registry.php '); require_once ('. /file_manager.php '); require_once ('. /base/session_memento.php '), class Copycommand extends Command {function do_execute (\controller\request $request) {$ Src_path = $request->get_property (' src '), $dst _path = $request->get_property (' DST '); $this->state->set (' Src_path ', $src _path); $this->state->set (' Dst_path ', $dst _path); $this->create_memento (); $file _manager = \ Base\registry::file_manager (); $ret = $file _manager->copy ($src _path, $dst _path); $request->add_feedback ($ret) ;//...}}
Command objects do a single job: Get the parameters (check parameters), save the necessary state information, and give control to the specific business logic object. Add the execution result and return. Different commands require different request parameters, and some commands do not need or support undo operations at all, so you can selectively perform create_memento operations.

Finally, the Undo-redo to be implemented, where I think of Undo/redo as an ordinary command request without the need for additional distribution processing in the controller.


Undo command:

Namespace woo\command;require_once (' request.php '); require_once (' command.php '); require_once ('.. /base/registry.php '); require_once ('. /base/session_memento.php '); class Undocommand extends Command{public function Do_execute (\controller\request $ Request) {$command = \base\sessionmementotaker::get_undo_command (), if (Isset ($command)) {$old _req = $command->get_ Request (); $command->do_unexecute ($old _req); $request->set_feedback ($old _req->get_feedback ());} else{$request->add_feedback (' Undo command Not Fount ');} return;}}

Redo Command:

Namespace woo\command;require_once (' request.php '); require_once (' command.php '); require_once ('.. /base/registry.php '), class Redocommand extends Command {public Function Do_execute (\woo\controller\request $request) { $command = \woo\base\sessionmementotaker::get_redo_command (), if (Isset ($command)) {$old _req = $command->get_ Request (); $command->do_execute ($old _req); $request->set_feedback ($old _req->get_feedback ());} else{$request->add_feedback (' Undo command Not Fount ');} return;}}

The end.



Full implementation of redo (redo) and undo (undo)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.