Chciałbym wdrożenia Map, w którym mogę dodać detektory zdarzeń put().Czy istnieje implementacja mapy ze słuchaczami dla Javy?
Czy jest coś takiego w standardowej lub dowolnej innej bibliotece?
Chciałbym wdrożenia Map, w którym mogę dodać detektory zdarzeń put().Czy istnieje implementacja mapy ze słuchaczami dla Javy?
Czy jest coś takiego w standardowej lub dowolnej innej bibliotece?
nie jestem świadomy żadnym standardzie bądź 3rd party, ale to jest proste, wystarczy utworzyć klasę, która otacza inną mapę i implementuje interfejs Mapa:
public class MapListener<K, V> implements Map<K, V> {
private final Map<K, V> delegatee;
public MapListener(Map<K, V> delegatee) {
this.delegatee = delegatee;
}
// implement all Map methods, with callbacks you need.
}
Zamiast 'implementuje Mapę
Guava's ForwardingMap jest w zasadzie właśnie tym - przekazuje wszystkie metody delegatowi, a następnie można je przesłonić. –
Tak właśnie myślałem, po prostu łowiąc kod wielokrotnego użytku przed napisaniem własnego :) –
Sezon do smaku. Jest to reprezentatywne, a nie normatywne. Oczywiście, że ma problemy.
public class ListenerMap extends HashMap {
public static final String PROP_PUT = "put";
private PropertyChangeSupport propertySupport;
public ListenerMap() {
super();
propertySupport = new PropertyChangeSupport(this);
}
public String getSampleProperty() {
return sampleProperty;
}
@Override
public Object put(Object k, Object v) {
Object old = super.put(k, v);
propertySupport.firePropertyChange(PROP_PUT, old, v);
return old;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
propertySupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
propertySupport.removePropertyChangeListener(listener);
}
}
Rozszerzenie nie jest dobre dla tego wymogu, uważam, że tworzenie opakowania dla każdej mapy jest znacznie lepsze. –
@AmirPashazadeh co masz na myśli przez "opakowanie dla każdej mapy"? –
Opakowanie, które akceptuje dowolną implementację mapy jako argument, więc domyślne zachowanie mapy pozostaje niezmienione. –
Co jesteś w istocie do ustalenia for to pamięć podręczna, która może dostarczać powiadomienia o zdarzeniach. Istnieje kilka produktów, takich jak Infinispan, które już zapewniają, że dla Ciebie, ale bez znajomości swojego przypadku użycia trudno polecić.
Jeśli potrzebujesz prostej mapy observable, powinna ona być łatwa do wdrożenia. Po prostu musisz stworzyć wzór obserwatora. Możesz znaleźć przykład: here.
Infinispan będzie świetny, ale potrzebuję tego wewnątrz apletu, więc mogę dostarczyć dane do .... infinispan! Tylko dlatego, że wywołania javascript są traktowane jako niepodpisany kod i nie mogę ich dostarczyć bezpośrednio :( –
Infinispan ma wbudowane i rozproszone tryby. Możesz osadzić Infinispan w swojej maszynie JVM. – uaarkoti
Oto działający przykład mapy, która uruchamia zdarzenia zmiany właściwości przy zakładaniu i usuwaniu. Realizacja podzielona jest na dwie klasy:
ListenerModel
Zawiera metody związane dodawanie i usuwanie słuchaczy, a także zmiany sposobu wypalania zmiany własności.
ListenerMap
Rozszerza ListenerModel i implementes interfejs java.util.Map delegowany. Wystrzeliwuje zmiany właściwości tylko w metodzie put and remove. Pożądane byłoby wywoływanie właściwości innymi metodami, np. clear(), putAll().
ListenerModel
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class ListenerModel {
private final PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener listener) {
changeSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
changeSupport.removePropertyChangeListener(listener);
}
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
changeSupport.firePropertyChange(propertyName, oldValue, newValue);
}
}
ListenerMap
import java.util.*;
public class ListenerMap<K, V> extends ListenerModel implements Map<K, V> {
public static final String PROP_PUT = "put";
public static final String REMOVE_PUT = "remove";
private Map<K, V> delegate = new LinkedHashMap<>();
@Override
public void clear() {
delegate.clear();
}
@Override
public boolean containsKey(Object key) {
return delegate.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return delegate.containsValue(value);
}
@Override
public Set<Entry<K, V>> entrySet() {
return delegate.entrySet();
}
@Override
public V get(Object key) {
return delegate.get(key);
}
@Override
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public Set<K> keySet() {
return delegate.keySet();
}
@Override
public V put(K key, V value) {
V oldValue = delegate.put(key, value);
firePropertyChange(PROP_PUT, oldValue == null ? null : new AbstractMap.SimpleEntry<>(key, oldValue),
new AbstractMap.SimpleEntry<>(key, value));
return oldValue;
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
delegate.putAll(m);
}
@Override
public V remove(Object key) {
V oldValue = delegate.remove(key);
firePropertyChange(REMOVE_PUT, oldValue == null ? null : new AbstractMap.SimpleEntry<>(key, oldValue),
null);
return oldValue;
}
@Override
public int size() {
return delegate.size();
}
@Override
public Collection<V> values() {
return delegate.values();
}
}
Oto JUnit 4 Test:
import org.junit.Before;
import org.junit.Test;
import java.beans.PropertyChangeListener;
import java.util.Map;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
/**
* Created by Gil on 01/07/2017.
*/
public class ListenerMapTest {
private ListenerMap<String, String> map;
@Before
public void setUp() throws Exception {
map = new ListenerMap<>();
}
@Test
public void whenPut_ShouldFireTrigger() throws Exception {
boolean[] fired = {false};
Map.Entry<String, String>[] listenEntry = new Map.Entry[1];
boolean[] checkNull = {true};
PropertyChangeListener propertyChangeListener = evt -> {
if (ListenerMap.PROP_PUT.equals(evt.getPropertyName())) {
if(checkNull[0]) {
assertThat(evt.getOldValue(), is(nullValue()));
}
else {
Map.Entry<String, String> oldValue = (Map.Entry<String, String>) evt.getOldValue();
assertThat(oldValue.getKey(), is("k1"));
assertThat(oldValue.getValue(), is("v1"));
}
listenEntry[0] = (Map.Entry<String, String>) evt.getNewValue();
fired[0] = true;
}
};
map.addPropertyChangeListener(propertyChangeListener);
map.put("k1", "v1");
assertThat(fired[0], is(true));
assertThat(listenEntry[0].getKey(), is("k1"));
assertThat(listenEntry[0].getValue(), is("v1"));
checkNull[0] = false;
map.put("k1", "v2");
}
@Test
public void whenRemove_ShouldNotFire() throws Exception {
boolean[] fired = {false};
PropertyChangeListener propertyChangeListener = evt -> {
fired[0] = true;
};
map.addPropertyChangeListener(propertyChangeListener);
map.put("k1", "v1");
assertThat(fired[0], is(true));
fired[0] = false;
map.removePropertyChangeListener(propertyChangeListener);
map.put("k2", "v2");
assertThat(fired[0], is(false));
}
}
Napisz klasę MapListenerAdaptor. –