2014-01-28 6 views
2

Joshua Bloch의 Effective Java에 설명 된 일반 유형의 안전한 컨테이너 패턴을 사용하고 싶지만 enum을 사용하여 키로 사용할 수있는 클래스를 제한하고 싶습니다. 아래는 Joshua의 책에서 발췌 한 코드입니다.타입 안전 이성 컨테이너의 키 제한

비슷한 클래스를 작성하고 싶지만 "Dog.class"및 "Cat.class"라고 말하도록 키를 제한하고 싶습니다. 이상적으로, 수용 가능한 키는 열거 형에 의해 기술되고 "RestrictedFavorites"클래스는 열거 형의 멤버를 키로 사용합니다. 컴파일러가 나를 위해 (타입 안전성, 열거 형, 제한에 의한 제한) 컴파일러를 얻을 수 있는지는 잘 모르겠지만 누군가에게 제안이 있다면, 나는 모두 귀입니다. 다음은 컴파일 타임 검사가 아닌 런타임 검사를 사용하는 V1 시도이며 완전히 만족스럽지 않습니다. (내 자신의 질문에)

public class RestrictedFavoritesTest extends TestCase { 

    public void testPutFavorite() { 
    RestrictedFavorites myFavorites = new RestrictedFavorites(); 
    myFavorites.putFavorite(RestrictedKey.INTEGER, 1); 
    myFavorites.putFavorite(RestrictedKey.STRING, "hey"); 
    int expectedInt = myFavorites.getFavorite(Integer.class); 
    assertEquals(1, expectedInt); 
    String expectedString = myFavorites.getFavorite(String.class); 
    assertEquals("hey", expectedString); 
    } 

    public void testPutFavorite_wrongType() { 
    RestrictedFavorites myFavorites = new RestrictedFavorites(); 
    try { 
     myFavorites.putFavorite(RestrictedKey.INTEGER, "hey"); 
     fail(); 
    } catch (IllegalArgumentException expected) {} 
    } 

    public void testPutFavorite_wrongClass() { 
    RestrictedFavorites myFavorites = new RestrictedFavorites(); 
    try { 
     myFavorites.getFavorite(Boolean.class); 
    } catch (IllegalArgumentException expected) {} 
    } 

} 
+2

은'지도'의 핵심으로'enum'을 사용하고'enum'의 속성에'Class' 유형을 저장합니다. –

+0

이 방법을 시도했습니다. 내 질문에 예제를 추가했지만 컴파일되지 않습니다. 내가 뭔가를 알아낼 수 있다면 더 좋은 버전을 반복하고 게시 할 것입니다. –

+0

'getFavorite'에서 리턴 타입을'T'로 변환하십시오. 'Map'이 몇 가지 공통적 인 부모 클래스없이 유지할 수있는 인스턴스를 제한하려면 런타임 검사에 의존해야합니다. 여러분은 그 메소드를'enum '에 넣을 수도 있습니다 - 코드를 조금 정리하면됩니다. –

답변

1

답변 :

import java.util.HashMap; 
import java.util.HashSet; 
import java.util.Map; 
import java.util.Set; 
/** 
* Attempt V1 At a "RestrictedFavorites" class 
*/ 
public class RestrictedFavorites { 

    public static enum RestrictedKey { 

    STRING(String.class), 
    INTEGER(Integer.class); 

    private static Set<Class<?>> classes; 
    static { 
     classes = new HashSet<>(); 
     for (RestrictedKey key: values()) { 
     classes.add(key.getKlass()); 
     } 
    } 

    private final Class<?> klass; 

    RestrictedKey(Class<?> klass) { 
     this.klass = klass; 
    } 

    public Class<?> getKlass() { 
     return klass; 
    } 

    public static boolean isValidClassKey(Class<?> klass) { 
     return classes.contains(klass); 
    } 

    } 

    private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>(); 

    //Ideally would use compile time checking 
    public <T> void putFavorite(RestrictedKey key, T instance) { 
    if (key == null) throw new NullPointerException("Type is null"); 
    if (!key.getKlass().equals(instance.getClass())) { 
     throw new IllegalArgumentException(
      "The type of the key must match the type of the instance"); 
    } 
    favorites.put(key.getKlass(), instance); 
    } 

    //Ideally would take a RestrictedKey as an argument 
    public <T> T getFavorite(Class<T> key) { 
    if (!RestrictedKey.isValidClassKey(key)) { 
     throw new IllegalArgumentException(
      "The key must be a member of RestrictedKeys"); 
    } 
    return key.cast(favorites.get(key)); 
    } 

} 

다음은 내 수업은 내가 그것을 원하는 거의 일을하고 있는지 확인하기 위해 몇 가지 단위 테스트입니다. 열거 형을 사용하지 마십시오. 열거 형은 일반적 일 수 없기 때문입니다. 대신 제한된 키를 나타내는 클래스를 만들고 생성자에 대한 액세스를 제한하십시오. 유효한 키를 필드로 열거하십시오.

import java.util.HashMap; 
import java.util.Map; 

public class RestrictedFavorites { 

    private static final class RestrictedKey<T> { 

    private final Class<T> type; 

    private RestrictedKey(Class<T> type) { 
     this.type = type; 
    } 

    private Class<T> getMyType() { 
     return this.type; 
    } 
    } 

    public static final RestrictedKey<String> STRING_KEY = 
     new RestrictedKey<>(String.class); 
    public static final RestrictedKey<Integer> INTEGER_KEY = 
     new RestrictedKey<>(Integer.class); 

    private final Map<RestrictedKey<?>, Object> favorites = 
     new HashMap<RestrictedKey<?>, Object>(); 

    public <T> void putFavorite(RestrictedKey<T> key, T instance) { 
    favorites.put(key, instance); 
    } 

    public <T> T getFavorite(RestrictedKey<T> key) { 
    return key.getMyType().cast(favorites.get(key)); 
    } 

} 

그리고 단위 테스트 :

public class RestrictedFavoritesTest extends TestCase { 

    public void testPutFavorite() { 
    RestrictedFavorites myFavorites = new RestrictedFavorites(); 
    myFavorites.putFavorite(RestrictedFavorites.STRING_KEY, "hey"); 
    myFavorites.putFavorite(RestrictedFavorites.INTEGER_KEY, 1); 
    assertEquals(new Integer(1), myFavorites.getFavorite(RestrictedFavorites.INTEGER_KEY)); 
    assertEquals("hey", myFavorites.getFavorite(RestrictedFavorites.STRING_KEY)); 
    } 

} 
+1

+1 또한 필드를 '최종'으로 지정하는 것을 잊지 마십시오. –

+0

완료. suggesions 주셔서 감사합니다. –

+0

허용되는'Class '의 정적 (또는 구성 가능한) 집합을 지정하는 것과 다른 점은 무엇입니까? 'Class' 객체에 래퍼를 추가하는 것뿐입니다. 나는 그것을 얻지 않는다. –