#java #map #guice #guava
#java #словарь #графический интерфейс #гуава
Вопрос:
Я хотел бы найти или реализовать, MutableGuiceKeyToInstanceMap
работающий точно так же, как com.google.common.collect.MutableClassToInstanceMap
из Guava, но использующий com.google.inject.Key<T>
из Guice вместо Class<T>
.
Я не смог найти это в Guice, и я не могу реализовать это так, как MutableClassToInstanceMap
было реализовано из-за того, что его суперкласс ConstrainedMap
является закрытым для пакетов. Я не могу использовать MapConstraint.constrainedMap
ни то, ни другое, поскольку у меня не было бы возможности добавить методы getInstance
и putInstance
(а без них все это совершенно бессмысленно).
Создание собственной копии ConstrainedMap
класса вынудило бы меня скопировать довольно много дополнительных классов, так что это не тот путь. Создание вспомогательной карты через MapConstraint.constrainedMap
и создание MutableGuiceKeyToInstanceMap extends ForwardingMap
, которое делегирует все помощнику, могло бы сработать, но это все еще довольно громоздко. Есть идея получше?
Как вы думаете, предложение сделать ConstrainedMap
общедоступным — хорошая идея?
Ответ №1:
Некоторые мысли:
- Мне любопытно, почему вы хотите это сделать.
- A
ForwardingMap
кажется подходящим для этого. Что в этом громоздкого? - Делать
ConstrainedMap
общедоступным было бы не очень хорошей идеей.
Комментарии:
1. 1. Для реализации пользовательской области. Хорошо, на самом деле это не нужно, поскольку нет никого, кто мог бы вставить туда что-нибудь неправильное. 2. Таким образом, я определяю два почти идентичных класса — один из них просто для того, чтобы было на что пересылать. Но это не так плохо, как я думал. 3. Почему бы и нет?
2. 1. На самом деле мне нужны только два метода,
getInstance
иputInstance
ни один из методов Map не требуется. Тем не менее, я хотел создать карту (понятия не имею, как вызвать такую «карту», в которой отсутствуют все методы Map). 2. На самом деле это действительно просто. 3. Я вижу, что для поддержания ограничения оно должно быть либо закрытым для пакета, либо все методы, изменяющие и раскрывающие мутатор (напримерentrySet()
), должны быть окончательными.
Ответ №2:
Я не понимаю, почему вам не нравится сочетание ForwardingMap
и MapConstraint.constrainedMap
. Код довольно прост и выглядит почти точно так же, как если бы вы расширяли ConstrainedMap
напрямую:
import com.google.common.collect.ForwardingMap;
import com.google.common.collect.MapConstraint;
import com.google.common.collect.MapConstraints;
import com.google.inject.Key;
import org.apache.commons.lang.NotImplementedException;
import java.util.HashMap;
import java.util.Map;
public final class MutableGuiceKeyToInstanceMap<B>
extends ForwardingMap<Key<? extends B>, B> {
/**
* Returns a new {@code MutableGuiceKeyToInstanceMap} instance backed by a {@link
* java.util.HashMap} using the default initial capacity and load factor.
*/
public static <B> MutableGuiceKeyToInstanceMap<B> create() {
return new MutableGuiceKeyToInstanceMap<B>(new HashMap<Key<? extends B>, B>());
}
/**
* Returns a new {@code MutableGuiceKeyToInstanceMap} instance backed by a given
* empty {@code backingMap}. The caller surrenders control of the backing map,
* and thus should not allow any direct references to it to remain accessible.
*/
public static <B> MutableGuiceKeyToInstanceMap<B> create(Map<Key<? extends B>, B> backingMap) {
return new MutableGuiceKeyToInstanceMap<B>(backingMap);
}
private final Map<Key<? extends B>, B> delegate;
private MutableGuiceKeyToInstanceMap(Map<Key<? extends B>, B> delegate) {
this.delegate = MapConstraints.constrainedMap(delegate, VALUE_MATCHES_GUICE_KEY);
}
@Override
protected Map<Key<? extends B>, B> delegate() {
return delegate;
}
private static final MapConstraint<Key<?>, Object> VALUE_MATCHES_GUICE_KEY = new MapConstraint<Key<?>, Object>() {
@Override
public void checkKeyValue(Key<?> key, Object value) {
matchesGuiceKey(key, value);
}
};
public <T extends B> T putInstance(Key<T> key, T value) {
return matchesGuiceKey(key, put(key, value));
}
public <T extends B> T getInstance(Key<T> key) {
return matchesGuiceKey(key, get(key));
}
private static <B, T extends B> T matchesGuiceKey(Key<T> key, B value) {
throw new NotImplementedException("TODO");
}
private static final long serialVersionUID = 0;
}
Код очень похож на MutableClassToInstanceMap
, и нет необходимости расширять ForwardingMap
… Конечно, вам нужно добавить delegate()
метод и сопровождающее его поле, но остальное идентично.
Я опустил matchesGuiceKey()
реализацию в качестве упражнения для читателя. Удачи! Вам может это понадобиться.
Комментарии:
1. Хороший ответ, это действительно не так уж плохо. Метод
matchesGuiceKey
может быть забавным упражнением, спасибо также за ссылки.2. @eneveu: Я не думаю, что я правильно выполнил упражнение, поскольку я использую там
@SuppressWarnings("unchecked") final Class<T> rawClass = (Class<T>) key.getTypeLiteral().getRawType();
. Кажется, это работает, но есть идея получше?3. На самом деле, реализовать
matchesGuiceKey
метод непросто. Я иронизировал в своем ответе. Ваш вопрос был сосредоточен на невозможности расширенияConstrainedMap
, и я ответил на эту часть вопроса. НоmatchesGuiceKey
материал на самом деле сложнее. Я попытался реализовать этот метод, но был час ночи, и я не смог заставить его работать. Я мог бы попробовать еще раз позже сегодня, но дженерики не сделают это легким 😉 И даже не заставляй меня рассказывать обо всейTypeLiteral
банке с червями… Если только мы не найдем специалиста по дженерикам?4. @eneveu: Я реализовал это здесь . Это может быть неправильно, но я так не думаю. Результат метода
TypeLiteral.getRawType()
требует непроверенного приведения, но это ИМХО нормально, поскольку он возвращает что-то вроде rawMap
для типа literal likeMap<K, ? extends E super S>
и нет способа выразить их взаимосвязь в системе Java generics.5. @eneveu: Остается только одна проблема: что-то вроде
m.put(stringListKey, integerList);
не должно быть возможным, но — из-за стирания — это возможно, и нет никакого способа обойти это, кроме запрета всех других мутаторовputInstance
.