C 계통의 언어에는 함수 포인터라는게 있습니다.
함수포인터 존나좋슴 ㅇㅇ
근데 자바에는 그런거 업ㅂ엉..

어떻게 하느냐?
방법1. 리플렉터를 이용합니다. (좆같에)
이런방법은 솔직히 말해서 별로 좋은방법도 아니고.. 프로그램의 안전성에도 별로 좋은방법은 아니지만 하나 만들어보겠습니다.

package a;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Callback {
	String message;
	static Method invocation1;
	static Method invocation2;
	static {
		try {
			Class<?>[] classes = null;
			invocation1 = Callback.class.getMethod("methode1", classes);
			
			invocation2 = Callback.class.getMethod("methode2", new Class[] { String.class });
			
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	Callback(String msg) {
		message = msg;
		
	}
	
	public void methode1() {
		System.out.println(message);
	}
	
	public void methode2(String message) {
		System.out.println(message);
	}
	
	public static void main(String[] args) {
		Callback c1 = new Callback("hello World");
		Callback c2 = new Callback("리플렉터 테스트");
		try {
			Callback.invocation1.invoke(c1);
			Callback.invocation1.invoke(c2);
			System.out.println("---------------------------");
			Callback.invocation2.invoke(c1, "test2");
			Callback.invocation2.invoke(c1, "test3");
			
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
요딴식으로 작성이 가능합니다.
일단 이걸하게되면 예외처리는 기본으로 따라와야합니다.

결과는 예상하는대로
hello World
리플렉터 테스트
---------------------------
test2
test3
이렇게 나옵니다.

요딴식이라고 헀듯이 사용하는데 위험성이 따릅니다. 일단은 메소드 이름을 찾는데 문자열로 찾아야한다 라는겁니다.
복붙 하면된다 라고 하지만 메소드 이름이 바뀐다면? 매소드의 인자가 바뀐다면? 컴파일은 되겠지만 리플렉터를 이용해서 직접 호출하기 전에는 경고조차 안뜰겁니다. 그리고는 뻥 하고 터지겠죠
그리고 invoke 에서 전달받는 인자는 그 메소드를 가지고있는 객체인데 이것도 타입체크가 안됩니다. 그냥 Object 면 일단 다들어가요.

아 추가로 사용할 메소드는 public 메소드여야 리플렉트에서 사용이 가능합니다.

이상태에서 다른 클레스로 invocation 객체를 넘겨줬다 칩시다. 첫번쨰 인자는 반드시 Callback 클레스의 객체를 넘겨줘야하는데 여기저기 넘겨주고 돌리다보면 이게 어디서온건지도 했갈리기 시작할겁니다.
프로그래머가 책임지도 제대로 써야한다는거죠


하여튼 리플렉터 라는 방법은 정말 이거아니면 답이 없을때 쓰는겁니다.

이보다 훨씬 좋은 방법이 있습니다. Interface 를 이용한 콜백입니다.
(솔직히 이걸 콜백이라고 부르는건지 잘 모르겠습니다. 그냥 내가 콜백이라고 부릅니다.)

방법2. 인터페이스를 이용해서 콜백을 작성한다.

interface Call1 {
	public void run(String message);
}

interface Call2 {
	public void run();
}

public class Callback2 {
	String message;
	Call1 call1 = new Call1() {
		@Override
		public void run(String message) {
			System.out.println(message);
		}
	};
	
	Call2 call2 = new Call2() {
		@Override
		public void run() {
			methode1();
		}
	};
	
	Callback2(String msg) {
		message = msg;
		
	}
	
	public void methode1() {
		System.out.println(message);
	}
	
	public void methode2(String message) {
		System.out.println(message);
	}
	
	public static void main(String[] args) {
		Callback2 c1 = new Callback2("hello World");
		Callback2 c2 = new Callback2("리플렉터 테스트");
		c1.call2.run();
		c2.call2.run();
		System.out.println("---------------------------");
		c1.call1.run("test2");
		c1.call1.run("test3");
	}
}

실행결과는 위와 동일합니다. 하지만 Call1,Call2 라는 인터페이스를 이용해서 객체를 생성한뒤 그 객체의 메소드를 호출한다.
필드(맴버변수)이지만 메소드 처럼 사용되는겁니다.
정말 C나 C++ 같으면 함수포인터만 쓰면 끝날 일이지만 자바에서는 좀 귀찬습니다.

하지만 Methode 를 이용하는것보다 프로그래머가 책임져야하는 일이 훨씬 줄어든다. 잘못된 인자를 넘겨줄 걱정도 안해도된다.

하여튼 Methode를 써서 invoke 하는 미친 코드가 있다면 Callback 인터페이스를 만들어서 전부 갈아엎어주자.
물론 지워버려서 하위호환이 안되게 하지는 말고..

위에 작성한것처럼 클레스 내부의 메소드를 호출해도 되고 그냥 거기에 바로 작성해도 됩니다.

추가1.
알고보니 이거 ㅇㅇ 함수 객체라고 부름. 디자인 패턴으로는 전략패턴이라고함

'Programming > Java' 카테고리의 다른 글

Java 의 Vector와 ArrayList의 차이점  (0) 2012.02.08
알파 체널을 통해서 이미지를 폴리곤으로 만들기  (0) 2012.01.19
"".equals ?  (0) 2011.12.21
초간단 원형 링크 리스트  (0) 2011.11.23
java에서 DES/AES 사용법  (0) 2011.11.22
Posted by 동적할당
: