자바와 같은 확정적 언어에서 사실 동적인 인스턴스 생성을 하기란 여간 어려운게 아닙니다. 보통은 팩토리 함수를 미리 정의해두는 것이 맞습니다만 클래스가 지속적으로 확장되거나 유지보수가 빈번하게 발생하는 경우는 팩토리 함수 자체를 관리하기도 귀찮은 일이죠. 이런 문제는 간단한 리플렉션(reflection)을 통해 단순화 시킬 수 있습니다.
생성자 해시맵 생성하기
우선 생성자를 리플렉션하기 전에 생성자함수를 모아둘 공간을 만들어둡니다.
@SuppressWarnings( "rawtypes" ) HashMap<String, Constructor> _constuctors = new HashMap<String, Constructor>();
위의 어노테이션은 기저타입을 사용하니 경고를 띄우지 말라는 뜻입니다.
클래스명을 배열에 저장하기
일단 Constructor를 담을 그릇은 나왔으니 대상이 될 클래스 이름을 배열에 넣을 차례입니다. 예에서 간단히 위젯을 감싼 래핑 클래스가 있다고 가정해보죠. 그 클래스들이 다음과 같이 존재한다고 합시다.
- com.bsidesoft.widget / bsButton.java
- com.bsidesoft.widget / bsCheckbox.java
- com.bsidesoft.widget / bsText.java
그럼 간단히 클래스 이름만 배열에 담습니다.
String[] t0 = {"bsButton", "bsCheckbox", "bsText"};
배열을 통해 해시맵 채우기
이제 배열을 루프돌며 해시맵에 생성자를 저장할 차례입니다.
try{ for( int i = 0, j = t0.length ; i < j ; i++ ) _constuctors.put( t0[i], Class.forName( "com.bsidesoft.widget." + t0[i] ).getConstructor() ); }catch( ClassNotFoundException $e ){ }catch( NoSuchMethodException $e ){ }
해시맵으로부터 인스턴스 생성하기
_constructor를 이용하면 간단히 인스턴스를 생성할 수 있습니다.
_instance = _constructor.get( "bsText" ).newInstance();
결론
위와 같은 리플렉션으로 배열만 관리하면 동적인 인스턴스 생성자를 쉽게 처리할 수 있게 됩니다(여타 문제도 발생하고 컴파일타임 시의 안정성도 약해지지만 알까보냐)
역시 리플렉션이 편하고 좋네요.
옷 여기에 댓글을 달면 되는 것인가?
완전 좋음! (참고로 지금 댓글을 전부 워드프레스에서 다는 중) _new = new HashMap();
위의 리플렉션은 참고 삼아 올린 내용으로 실무에서는 다음과 같이 사용하는 편이 성능상 유리합니다.
// new를 위한 간단한 인터페이스
interface N{ abstractType n(); }
// 생성자를 모아둘 해시맵
HashMap
//생성자 등록
_new.put( “child1”, new N(){ public abstracttype n(){ return new child1(); } } );
_new.put( “child2”, new N(){ public abstracttype n(){ return new child2(); } } );
_new.put( “child3”, new N(){ public abstracttype n(){ return new child3(); } } );
//인스턴스를 실제로 얻기
abstracttype t0 = _new.get( “child2” ).n();
사실 인터페이스 구상도 여러번하니 중복된 코드지만 반대로 개별적인 생성자에 대한 상세한 별도 설정을 할 수 있다는 점은 장점입니다.
음음 근데 말야 위의 포스팅이 연동될때 링크에 대한 설명이 안들어가 있잖아. 실수인가.