Thursday, July 02, 2009

Interface를 이용한 동적 ValueObject객체 생성

일반적으로 프로젝트에서 ValueObject객체를 만들어서 사용하게 되는데, 장점으로는 가벼운 객체
를 만들수있지만, 단점은 필드가 늘어나면 늘어날수록 getter/setter를 매번 만들어 주어야 하는
불편함이 있다.
 
아래 소스는 정의된 interface클래스 Sample만 사용해서 ValueObject형태로 만들어보는 예제 이다.
 
※ 테스트 하기 위해 만든 클래스
package com.shift.gef.xml;

public class SampleInstance {
 public static void main(String[] args) {
//  Sample sample = (Sample)InvokeHandler.getProxyInstance(com.shift.gef.xml.Sample.class);
  /**  또는 아래와 같이 해도 된다 **/
  Sample sample = (Sample)InvokeHandler.getProxyInstance("com.shift.gef.xml.Sample");
  sample.setExpr("test");
  sample.setSql("select * from dual");
  System.out.println(sample.getExpr());
  System.out.println(sample.getSql());
 }
}
 
※ 핵심이 되는 InvokeHandler 클래스
- InvokeHandler객체는 InvocationHandler인터페이스를 implements해서 작성하게 된다
- 아래 소스를 보면 알겠지만, invoke라는 메소드를 구현해 주어야 한다.
 
package com.shift.gef.xml;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
public class InvokeHandler implements InvocationHandler {
    HashMap map = null;
   
    private InvokeHandler() {
        map = new HashMap();
    }
   
    /**
     * 지정된 Interface클래스를 Proxy한 객체를 반환하는 메소드.
     * @param className Class Name - String Type임.
     * @return
     */
    public static Object getProxyInstance(String className) {
        try {
            Class [] it = new Class[1] ;
            it[0] = Class.forName(className);
       
            return Proxy.newProxyInstance(InvokeHandler.class.getClassLoader(), it, new InvokeHandler());
        } catch(ClassNotFoundException e) {
            System.out.println(e.fillInStackTrace());
            return null;
        }
    }
   
    /**
     * 지정된 Interface클래스를 Proxy한 객체를 반환하는 메소드.
     * @param className Interface class
     * @return
     */
    public static Object getProxyInstance(Class cls) {
        Class [] it = new Class[1] ;
        it[0] = cls;
        return Proxy.newProxyInstance(InvokeHandler.class.getClassLoader(), it, new InvokeHandler());
    }
   
    /**
     * 지정된 Interface클래스를 Proxy한 객체를 반환하는 메소드.
     * @param it    Interface Class[]
     * @return
     */
    public static Object getProxyInstance(Class it[]) {
        return Proxy.newProxyInstance(InvokeHandler.class.getClassLoader(), it, new InvokeHandler());
    }
   
    /**
     * Interface의 내용중 Getter/Setter에 대한 Invoke처리.
     */
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        /** Setter Method Invoke **/
        if (method.getName().indexOf("set") == 0) {
            map.put(method.getName().substring(3), args[0]);
            return null;
        /** Getter Method Invoke **/
        } else if (method.getName().indexOf("get") == 0) {
            return map.get(method.getName().substring(3));
        } else {
            throw new NoSuchMethodException("입력하신 메소드 [" + method.getName() + "]를  처리할수가 없습니다.\n[Getter/Setter Method]만 사용 가능합니다.\n해당 Interface의 내용을 확인해 주세요!");
        }
    }
}
 
 
 
※ 예제에서 사용된 Sample인터페이스 클래스
package com.shift.gef.xml;
public interface Sample {
    public String getExpr();
    public void setExpr(String s);
   
    public String getValue();
    public void setValue(String s);
   
    public String getType();
    public void setType(String s);
    public String getSql();
    public void setSql(String s);
}
인터페이스만 실제 예제를 돌려보면 인터페이스만 추가해 주면 일반적인 ValueObject객체와 같아
지는것을 볼수있다.
 
InvocationHandler를 어떤식으로 구현해서 응용하는냐에 따라 달려있음 ㅎㅎ

No comments: