ホームページ > バックエンド開発 > PHPチュートリアル > やり直しと元に戻すの完全な実装

やり直しと元に戻すの完全な実装

WBOY
リリース: 2016-08-08 09:32:36
オリジナル
978 人が閲覧しました
Undo-Redo をサポートするにはメモ モードとコマンド モードが必要です。私は以前にコマンド モードとメメント モードについての基本的な知識を学びました。ここでは、学習した知識を統合するために、2 つのモードを組み合わせて、元に戻す/やり直し操作用のモジュールを実装する必要があります。

システムブロック図:

コマンド分散コントローラーには主に 4 つのタスクがあります:
1. システムの初期化、システム構成パラメーターのロード、およびこれらのデータのキャッシュ、これらのアプリケーションレベルの構成パラメーターを使用できます。アクセス効率を高めるために、毎回ファイルを読み取る代わりにデータをキャッシュするシリアル化メカニズム。
2. フロントエンドリクエストに基づいてパラメータを収集し、リクエスト(Request)を生成します。
3. リクエストを特定のビジネス ロジックのコマンド モジュール (Command) にマッピングします。
4. 操作を実行し、結果をフロントエンド ビューに返します。

ビジネスロジック層は、受信したコンテキストオブジェクトに基づいて実行パラメータを取得でき、実行後、コンテキストオブジェクトを通じて前の層に実行結果を返すことができます。

コマンド分散コントローラーの実装:

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);
	}
}
ログイン後にコピー
コンストラクターをプライベートとして宣言することで、コントローラーはシングルトンになります。

PHP のようなインタープリタ型言語の場合、アンデオ/やり直しメカニズムを実装するには、コマンド実行の履歴を保存するために何らかのキャッシュ メカニズム (セッション) を使用する必要があります。ここでのセッション モジュールは主にコマンド履歴記録の維持を担当し、その実装は次のとおりです:

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;
	}
}
ログイン後にコピー

SessionMementoTaker の実装は、以前に実装されたセッション (URL 登録メカニズム) に基づいています。 Cookie に保存されたセッション ID に基づいて異なるオブジェクト データを復元すると、同じユーザーが同じオブジェクト データへのアクセスを複数回要求する目的を達成できます。 SessionMementoTaker は、3 つの追加インターフェイスを提供します。push_command 操作により、履歴コマンド リストにコマンドが追加されます。履歴コマンドリストの最大長は 5 です。5 を超えると、最初のコマンドが削除されます。また、push_command は、新しいコマンドを追加し、コマンド ポインタ (perent) を最新の位置に移動することに相当します。以前の状態を破棄します。 get_undo_command は最後に実行された履歴コマンドを取得し、ポインターを更新します。get_redo_command も同様です。
過去のコマンド リスト: command1---command2---command3---* アスタリスクは永続的であることを示し、実行される最新のコマンドを指します。
元に戻す操作: command1---command2-*--command3--- ロールバック後、永続ポインタは後方に移動します。
元に戻す操作: command1--*command2----command3--- ロールバック後、永続ポインターは後方に移動します。
やり直し操作: command1---command2-*--command3--- やり直しの後、永続ポインタは前に進みます。
Push_command: command1---command2---command3---command4---*persist がフロントエンドに更新されます
ここでは単一のコマンドオブジェクトが発信元とみなされます。必要に応じて積極的にメモを作成し、現時点での内部状態を保存し、コマンド オブジェクトを履歴コマンド レコード リストに追加します。

コマンド基本クラスの実装:

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::push_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();
	}
}
ログイン後にコピー

コマンドタスクは、実行の開始時に要求されたコマンドのパラメータを保存し、コマンドの実行中に他の必要なパラメータを保存することもできます。一部のコマンドは元に戻す操作をサポートしていないため、親クラスの実装には空の unexecute があります。

コマンドのステータスを保存するオブジェクト:

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;
	}
}
ログイン後にコピー

ファイルをコピーするための 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);
		//...
	}
}
ログイン後にコピー
コマンド オブジェクトのタスクは比較的単純です。パラメーター (検証パラメーター) を取得し、必要なステータス情報を保存し、特定のビジネス ロジック オブジェクトに制御を転送します。実行結果を追加して返します。コマンドが異なれば、必要なリクエスト パラメーターも異なります。一部のコマンドは、undo 操作を必要としない、またはまったくサポートしていないため、create_memento 操作を選択的に実行できます。

最後のステップは、undo-redo を実装することです。ここでは、コントローラーでの追加の分散処理を必要とせずに、undo/redo を通常のコマンド要求として扱います。


元に戻すコマンド:

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;
	}
}
ログイン後にコピー

やり直しコマンド:

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;
	}
}
ログイン後にコピー

最後です。 上記では、REDO と UNDO の完全な実装を、関連する内容も含めて紹介しています。PHP チュートリアルに興味のある友人に役立つことを願っています。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート