ภาพประมาณนี้ครับ
- ภาพบน คือไม่มี proxy (การทำงานจะเป็นการเรียกกันตรงๆ)
- ภาพล่าง มี proxy เป็นตัวคั่น (การทำงานจะผ่าน proxy ก่อน)
ผมขอยกตัวอย่างการจับเวลา (จับความเร็ว) รถยนต์แต่ละรุ่น โดยใช้ proxy design pattern เข้ามาช่วยครับ ซึ่งตอนที่ผมสั่งให้รถวิ่ง ผมจะให้มันจับเวลาเองโดยอัตฺโนมัติด้วย proxy method โดยที่เราไม่ต้องมา start / stop นาฬิกาจับเวลาเอง (ซึงถ้าเราเขียนแบบปกติ เราต้องมา start / stop เองทุกครั้ง ถ้ามีรถคันใหม่ถูกส่งเข้ามา)
ประกาศ interface Car ขึ้นมา สำหรับกำหนดว่า Car จะต้องมี method run
Car.java
package com.blogspot.na5cent.designpattern; /** * * @author Redcrow */ public interface Car { public void run(); }เขียน implementation Car แต่ละรุ่น ซึ่ง implements มาจาก interface Car
package com.blogspot.na5cent.designpattern; /** * * @author Redcrow */ public class Ferrari implements Car{ @Override public void run() { System.out.println("Ferrari running..."); } }
package com.blogspot.na5cent.designpattern; /** * * @author Redcrow */ public class Lamborghini implements Car{ @Override public void run() { System.out.println("Lamborghini running..."); } }
package com.blogspot.na5cent.designpattern; /** * * @author Redcrow */ public class BMW implements Car{ @Override public void run() { System.out.println("BMW running..."); } }...
...
...
TimerInvocationHandler.java
package com.blogspot.na5cent.designpattern; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * * @author Redcrow */ public class TimerInvocationHandler implements InvocationHandler { private Object object = null; public TimerInvocationHandler(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result; //before invoke System.out.println("start timer"); //***** result = method.invoke(object, args); //original method call (run method) System.out.println("stop timer"); //***** //after invoke return result; } }
เขียน class ไว้สร้าง car จับเวลา [แปลง (method) car ไปเป็น proxy]
CarTimer.java
package com.blogspot.na5cent.designpattern; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; /** * * @author Redcrow */ public class CarTimer { private Car transform(Car car) { Class clazz = car.getClass(); ClassLoader classLoader = clazz.getClassLoader(); Class<?>[] interfaces = clazz.getInterfaces(); InvocationHandler timerInvocationHandler = new TimerInvocationHandler(car); // Car carProxy = (Car) Proxy.newProxyInstance(classLoader, interfaces, timerInvocationHandler); return carProxy; } }
สั่งให้รถวิ่ง [ด้วย car.run()]
TestCar.java
package com.blogspot.na5cent.designpattern; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; /** * * @author Redcrow */ public class TestCar { public static void main(String[] args) { Car car = CarTimer.transform(new Lamborghini()); car.run(); //***** } }
สังเกตว่าเราเรียกแค่ car.run() แล้ว start timer / stop timer มันมาได้ยังไง ทั้งๆ ที่ใน method run ของรถแต่ละยี่ห้อ (Ferari, Lamborghini, BMW, ...) เราไม่ได้เขียน start / stop เอาไว้เลย
คำตอบคือ method run ถูกเรียกผ่าน proxy ยังไงล่ะครับ
pattern นี้ผมใช้อยู่ทุกวันครับ เพราะผมใช้ Spring Framework ในการพัฒนา application
ถ้าใครสงสัยว่า อ้าว แล้วมันใช้ตอนไหนล่ะ ไม่เคยเห็นเลย
ก็ตอนที่คุณเรียกใช้งาน @Service แล้วมีการใช้ @Transactional ยังไงล่ะครับ
คุณไม่สงสัยหรอว่า มันไป start / stop transaction ตอนไหน ?
กับถ้าคุณใช้ Spring Data คุณไม่สงสัยหรอว่า มันไป connect / close database ตอนไหน
บทความนี้คือคำตอบครับ
แต่ว่า Spring เขาเขียนแบบ AOP (Aspect Oriented Programming) อีกทีน่ะครับ
ลองไปศึกษากันเองดูครับ
เขียน java มันก็สนุกแบบนี้แหล่ะ
มาเขียน java กันเถอะครับ ^_^
ไม่มีความคิดเห็น:
แสดงความคิดเห็น