흥미로운 상황이 있으며 더 나은 방법이 있는지 궁금합니다. 상황은 이것입니다. 트리 구조 (특히 추상 구문 트리)가 있고 일부 노드에는 다양한 유형의 자식 노드가 포함될 수 있지만 모두 주어진 기본 클래스에서 확장됩니다.유형 안전성, Java generics 및 쿼리
이 트리에서 자주 쿼리를 수행하고 싶습니다. 관심이있는 특정 하위 유형을 되돌리고 싶습니다. 따라서 일반 쿼리 방법으로 전달할 수있는 조건부 클래스를 만들었습니다.
public <T extends Element> List<T> findAll(IElementPredicate pred, Class<T> c);
Class
인수가 바로 반환 형식을 나타 내기 위해 사용되었다 : 처음에 나는이처럼 보였다 쿼리 방법을했다. 이 접근 방법에 대해 저를 괴롭혔던 것은 모든 술어가 이미 특정 유형에 대한 것이므로 여기에 중복 정보가 있다는 것입니다.
List<Declaration> decls =
scope.findAll(new DeclarationPredicate(), Declaration.class);
그래서 나는이처럼 리팩토링 :
public <T extends Element> List<T> findAll(IElementPredicate<T> pred);
을 IElementPredicate
인터페이스는 다음과 같다 여기서처럼 전형적인 전화가 보일 수 있습니다 요점은 여기 술어 것을
public interface IElementPredicate<T extends Element> {
public boolean match(T e);
public String getDescription();
public Class<T> getGenericClass();
}
입니다
인터페이스가 확장되어Class
개체를 대신 제공합니다. 실제
findAll
메소드를 작성하는 데 약간의 작업이 필요하며, 술어 작성에 조금 더 많은 작업이 추가되지만, 본질적으로 작은 "일회성"일 뿐이며 쿼리 호출을 훨씬 더 멋지게 만듭니다. 여분의 (잠재적으로 여분의) 인수를 추가해야합니다.
List<Declaration> decls = scope.findAll(new DeclarationPredicate());
이전에이 패턴을 발견하지 못했습니다. 이것은 Java generics의 의미를 다루는 일반적인 방법인가요? 단지 내가 더 좋은 패턴을 놓치고 있는지 궁금해.
수수료가 필요하십니까?
업데이트 :
하나의 질문으로 클래스가 필요합니까? 그것은 일치하는 만 T 걸리는 사실이지만, 나는 그것을 호출하기 전에 개체가 T 있는지 확인해야합니다
public <T extends Element> List<T> findAll(IElementPredicate<T> pred) {
List<T> ret = new LinkedList<T>();
Class<T> c = pred.getGenericClass();
for(Element e: elements) {
if (!c.isInstance(e)) continue;
T obj = c.cast(e);
if (pred.match(obj)) {
ret.add(c.cast(e));
}
}
return ret;
}
: 여기 findall은의 구현입니다. 이를 위해서는 클래스의 "isInstance"및 "cast"메서드가 필요합니다 (가능한 한 멀리 말할 수 있음).
방문자를 빈번히 (실제로이 프로젝트에서) 사용하지만,이 특별한 경우 방문자 패턴은 필 요하다고 생각되는 것보다 훨씬 많은 코드와 복잡성을 추가합니다. –
나는 당신과 동의한다, 그것은 부작용이 큰 부작용을 일으키는 방식으로 전환된다. 당신이 원하는 것처럼 일반성을 뒤집기가 어렵습니다. 방문자가 없다면 늦은 바인딩이나 명시 적 형식 검사 (equals()가 작동하는 방식)가 필요하기 때문에 솔루션이 최고라고 믿습니다. 당신의 솔루션은 구현 자에게 부담을주는 대신 유형 검사를 중앙 집중화하므로 더 좋습니다. 이 문제는 일반적인 Comparable 구현에서도 볼 수 있습니다. –
그리고 늦은 바인딩을 통해 나는 Java가 참조 유형이 아닌 객체 유형에 기반한 오버로드 된 메소드 해석을 구현해야한다는 것을 의미했습니다. 이것은 기본적으로 코드에서 구현 한 것입니다. –