类型安全异质容器限制密钥 [英] Limiting Keys in Type Safe Heterogenous Containers

查看:131
本文介绍了类型安全异质容器限制密钥的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用Joshua Bloch的Effective Java中描述的通用类型的安全容器模式,但是希望通过使用枚举来限制可以用作键的类。以下是约书亚书中的代码。

I would like to use the generic type safe container pattern, described in Joshua Bloch's Effective Java, but would like to restrict the classes which can be used as keys by using an enum. Below is the code from Joshua's book.

public class Favorites {

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

  public <T> void putFavorite(Class<T> type, T instance) {
    if (type == null)
      throw new NullPointerException("Type is null");
    favorites.put(type, instance);
  }

  public <T> T getFavorite(Class<T> type) {
    return type.cast(favorites.get(type));
  }

}

我想写一个类似的类,但是限制键来说Dog.class和Cat.class。理想情况下,可接受的键将由枚举描述,RestrictedFavorites类将会将枚举的成员作为键。我不知道我是否可以让编译器为我做所有这些事情(类型安全,枚举的限制,通用性),但如果有人有建议,我就是耳朵。以下是尝试V1,它使用运行时检查而不是编译时间检查,并不完全令人满意。

I would like to write a similar class, but limit the keys to say "Dog.class", and "Cat.class". Ideally, the acceptable keys would be described by an enum, and the "RestrictedFavorites" class would take members of the enum as keys. I'm not sure if I can get the compiler to do all these things for me (type safety, restriction by enum, generality), but if anybody has a suggestion, I'm all ears. Below is attempt V1, which uses runtime checks rather than compile time checks, and is not entirely satisfactory.

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));
  }

}

以下是一些单元测试来验证我的课程大致上要做的是:

Below are some unit tests to verify that my class is doing roughly what I want it to:

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) {}
  }

}


推荐答案

回答(给自己的问题)。不要使用枚举。因为枚举不能通用。而是创建一个类来表示受限制的键,并限制对构造函数的访问。枚举有效的键作为字段。

Answer (to my own question). Don't use Enums. Because enums can't be generic. Instead, create a class to represent the restricted keys, and restrict access to the constructor. Enumerate the valid keys as fields.

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));
  }

}

单元测试: p>

And the unit tests:

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));
  }

}

这篇关于类型安全异质容器限制密钥的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆