[Java]_[初级]_[使用PropertyChangeSupport和VetoableChangeSupport来实现观察者模式]

Posted infoworld

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Java]_[初级]_[使用PropertyChangeSupport和VetoableChangeSupport来实现观察者模式]相关的知识,希望对你有一定的参考价值。

场景

  1. 同进程的不同模块之前的通讯目前常用做法就是通过观察者模式来发送消息, 在JDK9ObserverObservable类已经失效.所以已经不能使用它来进行注册和通知了。那么怎么办?

说明

  1. 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.
  1. 很明显可以看出,PropertyChangeSupport可以当作Observer用,而PropertyChangeListener当作Observable用.

  2. 对于可拒绝修改的属性(命令),可以使用VetoableChangeSupport来提供支持,它和PropertyChangeListener的最大不同点就是它的fireVetoableChange会抛出异常,当某个VetoableChangeListener监听如果不同意修改,那么可以抛出异常来达到拒绝修改的目的.

例子

  1. 这里例子分别使用了PropertyChangeSupportVetoableChangeSupport来模拟ObserverObservable的使用。实际业务中,当然OldValueNewValue可以使用自己的复合对象.

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

参考

  1. PropertyChangeSupport

  2. VetoableChangeSupport

  3. what-is-the-difference-between-propertychangelistener-and-vetoablechangelistener

  4. C/C++ 观察者模式在项目中实际使用例子

  5. Objective-C 观察者模式在项目中实际使用例子2

以上是关于[Java]_[初级]_[使用PropertyChangeSupport和VetoableChangeSupport来实现观察者模式]的主要内容,如果未能解决你的问题,请参考以下文章

[Java]_[初级]_[高效使用String.split的方法]

[Java]_[初级]_[并发下使用AtomicReference来保证原子读写对象]

[Java]_[初级]_[并发下使用AtomicReference来保证原子读写对象]

[Java语言特性]_[初级]_[可变参数的使用技巧]

[Java]_[初级]_[使用easyexcel生成或下载Excel文件]

[Java]_[初级]_[使用easyexcel生成或下载Excel文件]