หน้าเว็บ

วันพุธที่ 23 มกราคม พ.ศ. 2556

Proxy Design Pattern Java

        proxy design pattern เป็นการเขียนโปรแกรมรูปแบบ (pattern) หนึ่ง ไม่ว่าจะด้วยภาษาโปรแกรมมิ่งใดๆ ก็ตาม มีวัตถุประสงค์เพื่อ ทำหน้าที่ในการคั่นกลางระหว่าง "สิ่งที่เรียก" กับ "สิ่งที่ถูกเรียก"  เพื่อทำอะไรบางอย่างก่อนที่ request จากผู้เรียกจะถูกส่งไปถึงผู้ที่ถูกเรียก  (อ่านเองยังงงเอง T__T)

ภาพประมาณนี้ครับ
  • ภาพบน คือไม่มี 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


Ferrari.java
package com.blogspot.na5cent.designpattern;

/**
 *
 * @author Redcrow
 */
public class Ferrari implements Car{

    @Override
    public void run() {
        System.out.println("Ferrari running...");
    }
    
}


Lamborghini.java
package com.blogspot.na5cent.designpattern;

/**
 *
 * @author Redcrow
 */
public class Lamborghini implements Car{

    @Override
    public void run() {
        System.out.println("Lamborghini running...");
    }
    
}


BMW.java
package com.blogspot.na5cent.designpattern;

/**
 *
 * @author Redcrow
 */
public class BMW implements Car{

    @Override
    public void run() {
        System.out.println("BMW running...");
    }
    
}
...
...
...


เขียน class สำหรับจับเวลา [proxy method]

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 กันเถอะครับ ^_^

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

แสดงความคิดเห็น