Tôi muốn thực hiện Bản đồ trong đó tôi có thể thêm người nghe cho các sự kiện put().Có bản đồ triển khai thực hiện với người nghe cho Java không?
Có điều gì giống như vậy trong thư viện chuẩn hoặc bất kỳ thư viện nào của bên thứ ba không?
Tôi muốn thực hiện Bản đồ trong đó tôi có thể thêm người nghe cho các sự kiện put().Có bản đồ triển khai thực hiện với người nghe cho Java không?
Có điều gì giống như vậy trong thư viện chuẩn hoặc bất kỳ thư viện nào của bên thứ ba không?
Tôi không biết về bất kỳ tiêu chuẩn hoặc bên thứ 3, nhưng nó rất dễ dàng, chỉ cần tạo một lớp bao bọc khác Bản đồ và thực hiện các giao diện bản đồ:
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.
}
Thay vì 'thực hiện Bản đồ
Bản đồ chuyển tiếp của ổi về cơ bản chính xác điều này - nó chuyển tiếp tất cả các phương pháp cho các đại biểu, và sau đó bạn có thể ghi đè lên để hương vị. –
Đó là những gì tôi nghĩ, chỉ cần câu cá cho mã tái sử dụng trước khi viết của riêng tôi :) –
Phần thưởng thức. Đây là đại diện, không phải là tiêu chuẩn. Tất nhiên nó có vấn đề.
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);
}
}
Mở rộng không phải là điều tốt cho yêu cầu này, tôi tin rằng việc tạo một trình bao bọc cho mọi bản đồ là tốt hơn nhiều. –
@AmirPashazadeh ý bạn là gì bởi "trình bao bọc cho mọi bản đồ"? –
Trình bao bọc chấp nhận bất kỳ triển khai bản đồ nào làm đối số, do đó hành vi mặc định của bản đồ vẫn như cũ. –
gì bạn là chủ yếu hỏi cho là một Cache có thể cung cấp thông báo sự kiện. Có một số sản phẩm ra có như Infinispan đã cung cấp cho bạn nhưng không biết trường hợp sử dụng của bạn khó để khuyên bạn nên.
Nếu bạn muốn có một ObservableMap đơn giản, nó sẽ dễ thực hiện. Bạn chỉ cần tạo một mẫu Observer. Bạn có thể tìm thấy một ví dụ here.
Infinispan sẽ là tuyệt vời, nhưng tôi cần điều này bên trong một applet, vì vậy tôi có thể cung cấp dữ liệu đến .... infinispan! Chỉ vì các cuộc gọi javascript được coi là mã chưa ký tôi không thể gửi trực tiếp: ( –
Infinispan có cả chế độ nhúng và phân phối. Bạn có thể nhúng Infinispan vào JVM của mình. – uaarkoti
Đây là ví dụ hoạt động của bản đồ kích hoạt sự kiện thay đổi thuộc tính khi đặt và xóa. Việc thực hiện được chia thành hai lớp:
ListenerModel
Chứa các phương pháp liên quan đến việc thêm và loại bỏ các thính giả thay đổi và cũng là một phương pháp để bắn những thay đổi bất động sản.
ListenerMap
Mở rộng ListenerModel và implementes giao diện java.util.Map bởi đoàn. Nó chỉ kích hoạt thay đổi thuộc tính trong phương thức put và remove. Sẽ có ý nghĩa khi kích hoạt các thuộc tính trên các phương thức khác, ví dụ: 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();
}
}
Dưới đây là một thử nghiệm JUnit 4:
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));
}
}
Viết một lớp MapListenerAdaptor. –