Javaオブジェクトに対する操作の記録と再生
元ネタ
What Kind of Differences?
Consider the following class. It defines an object that is able to record all the messages ever sent to it, and then playback those messages to another object.
以下のクラスは、オブジェクトに送られた全てのメッセージを記録し、他のオブジェクトで再生することが出来るよう、定義されている。class VCR def initialize @messages = [] end def method_missing(method, *args, &block) @messages << [method, args, block] end def play_back_to(obj) @messages.each do |method, args, block| obj.send(method, *args, &block) end end end
Example Code
require 'src/vcr' vcr = VCR.new vcr.sub!(/Java/) { "Ruby" } vcr.upcase! vcr[11,5] = "Universe" vcr << "!" string = "Hello Java World" puts string vcr.play_back_to(string) puts stringOutput
Hello Java World HELLO RUBY Universe!
VCR
import java.lang.reflect.*; import java.util.*; public class VCR<T> { class Message { final Method method; final Object[] args; Message(Method method, Object...args) { this.method = method; this.args = args; } } final List<Message> messages = new ArrayList<Message>(); final T proxyInstance; @SuppressWarnings("unchecked") public VCR(Class<T> interfaceClass) { this.proxyInstance = createInstance(interfaceClass); } @SuppressWarnings("unchecked") T createInstance(Class<T>...interfaces) { return (T)Proxy.newProxyInstance( Thread.currentThread().getContextClassLoader(), interfaces, new InvocationHandler(){ public Object invoke( Object proxy, Method method,Object[] args ) throws Throwable { messages.add(new Message(method, args)); return null; } }); } public T rec() { return this.proxyInstance; } public <TImpl extends T> TImpl playBackTo(TImpl obj) { try { for (Message message : messages) { message.method.invoke(obj, message.args); } return obj; } catch (Exception e) { throw new RuntimeException(e); } } }
Runner
public class VCRRunner { interface Hoge { public void hoge(); public void fuga(); } static class HogeImpl implements Hoge { String s; public HogeImpl(String s) {this.s = s;} public void hoge() {s += ":hoge";} public void fuga() {s += ":fuga";} } public static void main(String[] args) { VCR<Hoge> hogeVCR = new VCR<Hoge>(Hoge.class); //記録... hogeVCR.rec().hoge(); hogeVCR.rec().fuga(); //再生... HogeImpl hoge1 = new HogeImpl("hoge1"); hogeVCR.playBackTo(hoge1); System.out.println(hoge1.s); //prints "hoge1:hoge:fuga" System.out.println(hogeVCR.playBackTo(new HogeImpl("ぬるぽ")).s); //prints "ぬるぽ:hoge:fuga" } }
Output
hoge1:hoge:fuga ぬるぽ:hoge:fuga