每当有一个值被修改时,可观察的映射(observable map)都会触发一个PropertyChangeEvent。我们也可以通过“as”关键字把一个普通的映射转换为一个可观察的映射:
// 不要忘了导入 import java.beans.* def map = [:] as ObservableMap map.addPropertyChangeListener({ evt -> println "${evt.propertyName}: ${evt.oldValue} -> ${evt.newValue}" } as PropertyChangeListener) map.key = 'value' // 输出 key: null -> value map.key = 'Groovy' // 输出 key: value -> Groovy
我们也可以把一个已存在的映射包装为一个ObservableMap
import java.beans.* def sorted = [a:1,b:2] as TreeMap def map = new ObservableMap(sorted) map.addPropertyChangeListener({ evt -> println "${evt.propertyName}: ${evt.oldValue} -> ${evt.newValue}" } as PropertyChangeListener) map.key = 'value' assert ['a','b','key'] == (sorted.keySet() as List) assert ['a','b','key'] == (map.keySet() as List)
最后一点,我们可以指定一个闭包作为一个附加的参数,它会像一个属性的过滤器一样,过滤当它们的值改变时是否应该触发一个PropertyChangeEvent,在与Expando一起使用的时候这点非常有用。这个过滤闭包可能需要2个参数(属性的名称和它的值)或更少(属性的值)。
import java.beans.* def map = new ObservableMap({!(it instanceof Closure)}) map.addPropertyChangeListener({ evt -> println "${evt.propertyName}: ${evt.oldValue} -> ${evt.newValue}" } as PropertyChangeListener) def bean = new Expando( map ) bean.lang = 'Groovy' // 输出 lang: null -> Groovy bean.sayHello = { name -> "Hello ${name}" } // 没有输出,事件被略过了 assert 'Groovy' == bean.lang assert 'Hello Groovy' == bean.sayHello(bean.lang)