Hashmap с конечным набором ключей, каждый из которых принимает только один тип значения? - PullRequest
1 голос
/ 11 июля 2011

Хорошо, это может быть немного сложно объяснить.Я ищу способ создать Hashmap некоторого вида, который будет заполнен ключами, которые я уже знаю (потому что они являются свойствами объекта, который я создаю).Каждый из этих известных ключей будет иметь значения либо String, либо int, либо float (которые будут автоматически помещаться в ящики), либо - позже - какой-то объект / функцию (я до сих пор не знаю, как я выполню эту часть,но в любом случае это будет дальше).Я также хочу установить, какой тип принимает каждый ключ (скажем, ключ «x» будет принимать только целочисленный тип значения, ключ «уравнение» будет принимать только строку и т. Д.).

Просто датьВ более широком контексте, моя цель - создать утилиту Tweener, так как я не нашел такой библиотеки в Java, кроме SumoTween, которая вообще не соответствует моим потребностям.Я пытаюсь строить свои классы так, как это делает Каурина.Если у вас есть лучшая альтернатива, которая сэкономила бы мне время и проблемы, пожалуйста, не стесняйтесь поделиться (будь то о Tweeners или о моем вопросе о Hashmap).Кстати, я делаю этот Tweener, чтобы использовать его в Android-игре, которую я создаю, для создания анимации на растровых / рисованных объектах (не могу использовать классы анимации для этих объектов).

PS: это мой первый вопрос на этом сайте, надеюсь, я не слишком растерялся;Пожалуйста, потерпите меня.

Ответы [ 6 ]

4 голосов
/ 11 июля 2011

Почему вы используете для этого хэш-карту?Если вы знали «ключи», просто создайте класс с этими членами, и затем вы сможете набирать их по своему усмотрению.

Если вам действительно необходимо использовать хэш-карту по какой-то причине, вы можете просто расширить ее и переопределитьМетод put () для проверки ваших магических значений.Но я настоятельно рекомендую против этого, это плохой дизайн.

0 голосов
/ 11 июля 2011

Я бы предпочел не использовать карту напрямую. То, что вы ищете, вероятно, является чем-то более специфичным для приложения:

Предположим, что все, что вы создаете, предназначено для нескольких настроек. Ваша «Настройка» будет иметь предопределенный набор ключей. Каждый ключ предопределен, чтобы принять соответствующее значение настройки определенного значения. Если указан неправильный тип, будет сгенерировано исключение.

Я думаю, что примерно так разумно:

enum SettingValueType {
  public boolean isCorrectType(Object obj) {
    return true if obj is correct type represented by this enum 
  }
  STRING, INT, FLOAT   // add support to other type if u want
};

clsss SettingValue {
  SettingValueType type;
  Object value;
}

class SettingRepo {  // a repository of setting entries
  private Map<String, SettingValueType> allowedKeyAndType;
  private Map<String, Object> settings;

  SettingRepo() {
    // setup allowedKeyAndType programmatically or from config etc, depends on your design
  }

  public SettingValue setSetting(String key, Object value)  {

    SettingValueType valueType = allowedKeyAndType.get(key);
    if (valueType == null) {
      throw new KeyNotAllowedException();
    }

    if (v!alueType.isCorrectType(value) {
      throw new ValueIncorectTypeException();
    }

    return settings.put(key, new SettingValue(valueType, value));
    }
  } 

  public SettingValue getSetting(String key) {
    // u may throw exception if key is not in predefined set

    return settings.get(key);
  }

  // u may consider adding some convinient methods too:
  public String setStringSetting(String key, String value) {
    if alllowedKeyAndType do not contains key {
      throw KeyNOtAllowedException
    }
    if type is not STRING {
      throw IncorrectTypeExceptin
    }
    settings.put(key, new SettingValue(STRING, value))
  }

  public String getStringSetting(String key) {
    // should be straight forward now, right?
  }    
}

Есть много мест, которые можно улучшить в зависимости от вашего использования: если ваши типы очень динамичны, вы можете сделать SettingValueType чем-то вроде набора стратегий или использовать Class напрямую. setSetting () можно сделать универсальным и использовать Class в качестве дополнительного параметра и т. д. Но, по крайней мере, это должно дать вам отправную точку.

0 голосов
/ 11 июля 2011

Вы можете иметь отдельные карты, одну для строк; другой для целых чисел и т. д. И при добавлении к любой из этих карт вы можете добавить ключ к (глобальному) набору, чтобы гарантировать, что ни один ключ не будет дублирован между картами. Я подозреваю, что это не очень хорошо соответствует вашим потребностям (и, конечно, поиск немного сложнее), но если он работает для вас, отлично.

Возможно, лучшим вариантом будет добавить еще один уровень косвенности. Сделайте вашу карту Hashmap, где YourThing имеет подклассы для каждого из типов, которые вы хотите сохранить. Итак, StringYourThing имеет элемент данных String; IntegerYourThing имеет элемент данных int и т. д. Я не удивлюсь, обнаружив, что YourThing начинает использовать функциональность, которая в настоящее время является оператором переключения где-то внутри другого класса, который пытается согласованно работать со всеми этими различными типами данных. Если этот класс может просто взаимодействовать с YourThing, он может стать проще. Но это трудно понять, не увидев ваш код.

0 голосов
/ 11 июля 2011

Я бы сказал, создайте пользовательский класс, который наследует, скажем, HashMap, при вставке вы проверяете указанный ключ / значение, если оно действительно.

public static final HashMap<String, Class<?>> allowedTypes = new HashMap<String, Class<?>>() {{
    put("key1", String.class);
    put("key2", Integer.class);
    // etc
}};

public class CustomHashMap extends HashMap {
    public Object put(Object key, Object value) {
        Class<?> type = allowedTypes(key);

        if(type != null && !type.isInstance(value))
            throw new IllegalArgumentException("Invalid type for key " + key);

        return put(key, value);
    }

    private void PutAll(Map m) {
        for(Entry<?, ?> entry : m.entrySet())
            put(entry.getKey(), entry.getValue());
    }
}
0 голосов
/ 11 июля 2011

Я не совсем уверен, что это то, что вы просите, но звучит так, как будто вы можете использовать какой-то интерфейс / абстрактный класс для ключа и реализовать / расширить его соответствующим образом для каждого типа ключа, например:

public interface Key {}

private static final class StringKey implements Key {
    private final String value;

    public StringKey(String value) {
        this.value = value;
    }

    // hashCode, equals here
}

// IntegerKey, FloatKey, etc similarly

Тогда есть что-то вроде:

HashMap<Key, Integer> map = new HashMap<Key, Integer>();
0 голосов
/ 11 июля 2011

Если я правильно вас понимаю, вы в основном ищете HashMap. Это правильно?

PS Да, я знаю, что использование "объекта" таким образом не очень красиво.

...