ภาพประมาณนี้ครับ
- ภาพบน คือไม่มี 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 Carpackage 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 กันเถอะครับ ^_^







ไม่มีความคิดเห็น:
แสดงความคิดเห็น