java EventListener监听器模式和Observer观察者模式

sancaiodm Java 2021-12-10 1022 0

Java EventListener监听器

监听器用于监听应用中某些对象的属性或行为等动作的发生,然后作出相应的响应处理。


2、Java中的事件

Java监听器的组成有三部分:事件源、事件对象 事件监听器、    

事件机制中有3种角色

1,event source:就是事件产生的地方(事件源)

2,event object:就是具体的事件(事件对象)

3,event listener:就是对事件产生之后应该干什么(监听者)

我们可以简单这样描述:在事件产生的地方eventsource,如果发生了eventobject事件,就执行eventlistener方法里面的事情,这里会加上就是只定在哪或者在什么情况下出现事件才去干某件事情,


Java中监听接口是继承java.util.EventListener的类-监听者,事件类是继承java.util.EventObject的类-被监听者。但实际这两个类并中没有任何的抽象方法,所有事件侦听器接口都必须扩展的标记接口类,以此表明自己的身份【继承不继承并不影响实际功能实现,这只一种约束,一种规范】。


Observer 观察者

java.util.Observabl类的子类为 被观察者  即可以被观察的东西,有时候还会称之为主题,即Subject

java.util.Observer接口的实现类为 观察者   也称它为订阅者,即Subscribe


主题(Subject):一对多中的一,持有数据,当数据更新时,通知已注册的观察者

观察者(Observer):一对多中的多,接收主题数据做出响应

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象,不好理解?那打个比方:一个电脑主机,多个显示器.

image.png

第一种观察者模式实现方式(非java API实现方式)

public interface Observer {
    //当主题状态改变时每一个观察者做出相应处理,每个观察者都需要实现该方法
    public void update(int week);
}
public class ReaderObserver implements Observer {

    //持有一个主题对象的引用,关联关系
    private Subject baoshe;
    //读者人名
    private String readerName;
    //构造器用来注册观察者
    public ReaderObserver(String name,Subject baoshe) {
        this.readerName=name;
        this.baoshe = baoshe;
        //报社将所有的读者添加到观察者名单中
        baoshe.addObserver(this);
    }

    @Override
    public void update(int week) {
        System.out.println(readerName+"已拿到第"+week+"周刊");
        
    }
}
public interface  Subject {
    //添加观察者
    void addObserver(Observer obj);
    //移除观察者
    void deleteObserver(Observer obj);
    //当主题方法改变时,这个方法被调用,通知所有的观察者
    void notifyObserver();
}
public class XinhuaSheSubject implements Subject {

	//用来存放和记录观察者
    private List<Observer> observers = new ArrayList<Observer>();
    private int week;
	@Override
	public void addObserver(Observer obj) {
		// TODO Auto-generated method stub
		if(!observers.contains(obj)) {
			 observers.add(obj);
		}
		
	}
	@Override
	public void deleteObserver(Observer obj) {
		// TODO Auto-generated method stub
		if(!observers.contains(obj)) {
			 observers.remove(obj);
		}
	}
	@Override
	public void notifyObserver() {
		// TODO Auto-generated method stub
		for(int i=0;i<observers.size();i++){
            Observer reader=(Observer)observers.get(i);
            reader.update(week);
        }
	}
    
	//出版周刊,需要调用notifyObserver()方法,通知所有观察者(订阅者)更新状态
    public void setWeek(int week){
        this.week=week;
        System.out.println("第"+week+" 周报,已出刊");
        this.notifyObserver();
    }
}

客户端触发类:

public class ClientTestObserver {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
	XinhuaSheSubject xinhuashe=new XinhuaSheSubject();
        ReaderObserver zhangSan=new ReaderObserver("张三", xinhuashe);
        ReaderObserver LiSi=new ReaderObserver("李四", xinhuashe);
        ReaderObserver WangWu=new ReaderObserver("王五", xinhuashe);
        //出刊第7周周刊
        xinhuashe.setWeek(7);
        //出刊第8周周刊
        xinhuashe.setWeek(8);
	}
}


第二种观察者模式实现方式(java API实现方式)

java api的观察者模式:

  在java.util包中包含有基本的Observer接口和Observable抽象类.功能上和Subject接口和Observer接口类似.不过在使用上就方便多了,因为许多功能比如说注册,删除,通知观察者的那些功能已经内置好了.

  使用javaAPI的观察者模式需要明白这么几件事情:

   如何使对象变为观察者?

    实现观察者接口(java.util.Observer),然后调用Observable对象的addObserver()方法.不想再当观察者时,调用deleteObserver()就可以了.

   被观察者(主题)如何发出通知?

    第一步:先调用setChanged()方法,标识状态已经改变的事实.

    第二步:调用notifyObservers()方法或者notifyObservers(Objectarg),这就牵扯到推(push)和拉(pull)的方式传送数据.如果想用push的方式"推"数据给观察者,

可以把数据当做数据对象传送给notifyObservers(Object    arg)方法,其中的arg可以为任意对象,意思是你可以将任意对象传送给每一个观察者.如果调用不带参数的notifyObserver()方法,则意味着你要使用pull的方式去主题对象中"拉"来所需要的数据.

   观察者如何接收通知?

     观察者只需要实现一个update(Observable o,Object arg)方法,第一个参数o,是指定通知是由哪个主题下达的,第二个参数arg就是上面notifyObserver(Object arg)里传入的数据,如果不传该值,arg为null.

上部分内容转自:设计模式--观察者模式初探和java Observable模式

//被观察者类
public class NewsPaper extends Observable {

    private int week;
    
    //通过此方法来处理setChanged与notifyObservers方法
    public void setWeek(int week) {
        this.week=week;
        System.out.println("新华社报社2021年第 "+week+" 周报");
    	setChanged();
        //pullNotfication();
        pushNofication(week);
    }
    
    private void pullNotfication() {
        notifyObservers();
    }
    
    private void pushNofication(int arg) {
    	notifyObservers(arg);
    }
    
    public int getWeek() {
        return week;
    }
}
//观察者类
public class Reader implements Observer {

	//观察者类中持有被观察者的引用对象
	private Observable observable;
	private String readerName;
	
	public Reader(String readerName ,Observable observable) {
		this.readerName = readerName;
        this.observable = observable;
        //在被观察者中注册当前观察者
        this.observable.addObserver(this);
    }
	
	@Override
	public void update(Observable o, Object arg) {
		// TODO Auto-generated method stub
		//pull方式获取数据的变化
		NewsPaper newPaper = (NewsPaper)o;
		System.out.println(readerName+"拿到了新华社的第 "+newPaper.getWeek()+" 周报, 此方式是自己去买报:pull方式");
		
		//push接收数据的变化
		System.out.println(readerName+"拿到了新华社的第 "+arg+" 周报,, 此方式是送货上门:push方式");
	}
}

客户端使用类

public class ClientTest {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		NewsPaper newPaper = new NewsPaper();
		Reader sd = new Reader("老王",newPaper);
		newPaper.setWeek(40);
	}
}


观察者模式的介绍:

android 源码设计模式之--观察者模式

评论