[Java]_[初级]_[使用PropertyChangeSupport和VetoableChangeSupport来实现观察者模式]
Posted infoworld
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Java]_[初级]_[使用PropertyChangeSupport和VetoableChangeSupport来实现观察者模式]相关的知识,希望对你有一定的参考价值。
场景
- 同进程的不同模块之前的通讯目前常用做法就是通过观察者模式来发送消息, 在
JDK9
里Observer
和Observable
类已经失效.所以已经不能使用它来进行注册和通知了。那么怎么办?
说明
- 在
Observer
类的说明里有以下的描述. 即在同步线程里可以使用java.beans
包里进行处理事件模型. 而这个包下可以发现基本实现类是PropertyChangeSupport
. 使用它来注册某个属性的修改监听,当然也可以把属性名换为监听的命令,比如kCommandTypeGetSiteInfo
这种字符串;之后就是通过firePropertyChange()
方法来发送通知。这时,已注册过的PropertyChangeListener
监听就会被调用执行。
This class and the Observer interface have been deprecated. The event model supported by Observer and Observable is quite limited, the order of notifications delivered by Observable is unspecified, and state changes are not in one-for-one correspondence with notifications. For a richer event model, consider using the java.beans package. For reliable and ordered messaging among threads, consider using one of the concurrent data structures in the java.util.concurrent package. For reactive streams style programming, see the java.util.concurrent.Flow API.
-
很明显可以看出,
PropertyChangeSupport
可以当作Observer
用,而PropertyChangeListener
当作Observable
用. -
对于可拒绝修改的属性(命令),可以使用
VetoableChangeSupport
来提供支持,它和PropertyChangeListener
的最大不同点就是它的fireVetoableChange
会抛出异常,当某个VetoableChangeListener
监听如果不同意修改,那么可以抛出异常来达到拒绝修改的目的.
例子
- 这里例子分别使用了
PropertyChangeSupport
和VetoableChangeSupport
来模拟Observer
和Observable
的使用。实际业务中,当然OldValue
和NewValue
可以使用自己的复合对象.
ObserverObjectTest.java
package com.example;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
import org.junit.jupiter.api.Test;
public class ObserverObjectTest
@Test
public void testObserver()
Product product = new Product();
Customer customer = new Customer();
// Observer Observable
product.addPropertyChangeListenr(customer.getpListener());
product.addVetoChangeListenr(customer.getvListener());
//1. 修改内容并通知观察着.
product.setPrice(100);
PRINT("produce.price: "+product.getPrice()+"");
PRINT("customer.myPrice: "+customer.getMyPrice()+"");
//2. 不符合要求的通知或属性修改允许拒绝.
PRINT("product set name is Hello");
product.setName("Hello");
PRINT("produce.name: "+product.getName()+"");
PRINT("customer.name: "+customer.getMyName()+"");
PRINT("product set name is World");
product.setName("World");
PRINT("produce.name: "+product.getName()+"");
PRINT("customer.name: "+customer.getMyName()+"");
product.removePropertyChangeListenr(customer.getpListener());
product.removeVetoChangeListenr(customer.getvListener());
private static void PRINT(String str)
System.out.println(str);
public static class Product
PropertyChangeSupport pcs = new PropertyChangeSupport(this);
VetoableChangeSupport vcs = new VetoableChangeSupport(this);
int price;
String name;
public void addPropertyChangeListenr(PropertyChangeListener listener)
pcs.addPropertyChangeListener("price", listener);
public void removePropertyChangeListenr(PropertyChangeListener listener)
pcs.removePropertyChangeListener("price",listener);
public void addVetoChangeListenr(VetoableChangeListener listener)
vcs.addVetoableChangeListener("name",listener);
public void removeVetoChangeListenr(VetoableChangeListener listener)
vcs.removeVetoableChangeListener("name",listener);
public String getName()
return name;
public boolean setName(String name)
String oldName = this.name;
try
vcs.fireVetoableChange("name", oldName, name);
catch (PropertyVetoException e)
//e.printStackTrace();
return false;
this.name = name;
return true;
public int getPrice()
return price;
public void setPrice(int price)
int oldPrice = this.price;
this.price = price;
pcs.firePropertyChange("price", oldPrice, price);
public static class CustomerPropertyChangeListener implements PropertyChangeListener
public Customer customer;
public CustomerPropertyChangeListener(Customer customer)
this.customer = customer;
@Override
public void propertyChange(PropertyChangeEvent evt)
Integer price = (Integer)evt.getNewValue();
customer.myPrice = price;
PRINT("propertyName: "+evt.getPropertyName()
+ " oldValue: "+evt.getOldValue()+ " newValue: "+evt.getNewValue());
public static class CustomerVetableChangeListener implements VetoableChangeListener
Customer customer;
public CustomerVetableChangeListener(Customer customer)
this.customer = customer;
@Override
public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException
String name = (String)evt.getNewValue();
PRINT("propertyName: "+evt.getPropertyName()
+ " oldValue: "+evt.getOldValue()+ " newValue: "+evt.getNewValue());
if(!name.equals("World"))
throw new PropertyVetoException("Not same", evt);
customer.myName = name;
public static class Customer
CustomerPropertyChangeListener pListener;
CustomerVetableChangeListener vListener;
int myPrice;
String myName;
public CustomerPropertyChangeListener getpListener()
return pListener;
public void setpListener(CustomerPropertyChangeListener pListener)
this.pListener = pListener;
public CustomerVetableChangeListener getvListener()
return vListener;
public void setvListener(CustomerVetableChangeListener vListener)
this.vListener = vListener;
public String getMyName()
return myName;
public void setMyName(String myName)
this.myName = myName;
public int getMyPrice()
return myPrice;
public void setMyPrice(int myPrice)
this.myPrice = myPrice;
public Customer()
pListener = new CustomerPropertyChangeListener(this);
vListener = new CustomerVetableChangeListener(this);
输出
produce.price: 100
customer.myPrice: 100
product set name is Hello
propertyName: name oldValue: null newValue: Hello
produce.name: null
customer.name: null
product set name is World
propertyName: name oldValue: null newValue: World
produce.name: World
customer.name: World
参考
以上是关于[Java]_[初级]_[使用PropertyChangeSupport和VetoableChangeSupport来实现观察者模式]的主要内容,如果未能解决你的问题,请参考以下文章
[Java]_[初级]_[高效使用String.split的方法]
[Java]_[初级]_[并发下使用AtomicReference来保证原子读写对象]
[Java]_[初级]_[并发下使用AtomicReference来保证原子读写对象]