と思い、ググッてみたら、次のurlが参考になりそう。
泥船 - PerlでCommandパターン
└ http://d.hatena.ne.jp/hachi_ukkari/20090221/1235199125
あしあと日記 - Undo,Redoの実装って何十回もやってる気がする
└ http://d.hatena.ne.jp/Youchan/20081110/1226282911
あしあと日記 - Undo,Redoの実装つづき
└ http://d.hatena.ne.jp/Youchan/20081111/1226388917
Bug Catharsis - Undo,Redoの実装って何回かしかやってない気がする...
└ http://d.hatena.ne.jp/zecl/20091002/p1
※WEB+DB PRESS vol.6にもperlによるデザインパターンが記載されており、その中でcommandパターンも簡単に紹介されています。
interfaceのないperlやjavascriptで、Commandパターンによるundoを実装するなら、クラス構成は次のようになるかな? 実際に実行すると、いろいろと変更点が出てくると思いますが
これまでMVCでは描いていましたが、controlerにある各action methodを子クラス化にすることで実現できるかな?
例 2013/11/29追記
http://alexanderbrevig.github.io/CommandManager.js/examples/
var CommandManager = (function() { function CommandManager() {} CommandManager.executed = []; CommandManager.unexecuted = []; CommandManager.execute = function execute(cmd) { cmd.execute(); CommandManager.executed.push(cmd); }; CommandManager.undo = function undo() { var cmd1 = CommandManager.executed.pop(); if (cmd1 !== undefined){ if (cmd1.unexecute !== undefined){ cmd1.unexecute(); } CommandManager.unexecuted.push(cmd1); } }; CommandManager.redo = function redo() { var cmd2 = CommandManager.unexecuted.pop(); if (cmd2 === undefined){ cmd2 = CommandManager.executed.pop(); CommandManager.executed.push(cmd2); CommandManager.executed.push(cmd2); } if (cmd2 !== undefined){ cmd2.execute(); CommandManager.executed.push(cmd2); } }; return CommandManager; })();
<!DOCTYPE html> <html lang="en"> <head> <meta charset=utf-8 /> <title>CommandManager.js</title> <link href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css" rel="stylesheet"> <style> body { padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */ } </style> </head> <body> <div class="navbar navbar-inverse navbar-fixed-top"> <div class="navbar-inner"> <div class="container"> <a class="brand" href="#">CommandManager.js</a> </div> </div> </div> <div class="container"> <button id="addNumbers" class="btn">Add numbers</button> <button id="addText" class="btn">Add text</button> <button id="redo" class="btn">Redo</button> <button id="undo" class="btn">Undo</button> <div style="margin:1em 0;"> <pre id="text"></pre> </div> </div> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script src="../CommandManager.js"></script> <script type="text/javascript"> $(function(){ $("#addNumbers").click(function(){ CommandManager.execute({ execute: function(){ $("#text").append("\n0123456789"); }, unexecute: function(){ //t.split("\n").slice(0,2) var arr = $("#text").html().split("\n"); var html = arr.slice(0,arr.length-1).join("\n"); $("#text").html(html); } }); }); $("#addText").click(function(){ CommandManager.execute({ execute: function(){ $("#text").append("\ntext from command"); }, unexecute: function(){ var arr = $("#text").html().split("\n"); var html = arr.slice(0,arr.length-1).join("\n"); $("#text").html(html); } }); }); $("#redo").click(function(){ CommandManager.redo(); }); $("#undo").click(function(){ CommandManager.undo(); }); }); </script> </body> </html>
例(その2)
wysiwygエディタのCKEditorのpluginにundoがあるので、こちらも参考になるかもしれません。pluginのsrcは読んでおらず、command patternでもないかもしれませんが
http://ckeditor.com/addon/undo