JAVA设计模式之观察者模式

观察者模式在实际工作中其实经常会遇到,凡是和事件相关的,基本上都与观察者模式沾边。观察者模式主要用于解决某个对象触发了一个事件,需要其他的对象来协同处理。

UML图如下

举个简单的例子,小孩半夜醒来开始哭,那么他的父母就会立马过来照看他,例如爸爸给他讲笑话,妈妈给他喂奶,这时候小孩就是父母的观察对象。

从程序的角度来说,小孩是被观察者,父母是观察者,同时也可以添加其他的观察者。首先先将观察者抽象成接口,只有一个方法用作处理。同时,父母是观察者的实现,具有不同的处理方式。

public interface Observer {
	
	void dealWith();
}

public class Dad implements Observer{

	@Override
	public void dealWith() {
		System.out.println("Dad tell jokes");
	}

}

public class Mom implements Observer {

	@Override
	public void dealWith() {
		System.out.println("Mom feed...");
	}

}

小孩需要将这些观察者都存起来,到触发的时候直接依次调用他们的处理方法即可。

public class Child {
	
	private List<Observer> observers = new ArrayList<>();
	
	{
		observers.add(new Dad());
		observers.add(new Mom());
	}
	
	public void cry() {
		System.out.println("child is crying");
		for (Observer observer : observers) {
			observer.dealWith();
		}
	}

}

测试一下

public class Main {

	public static void main(String[] args) {
		Child child = new Child();
		child.cry();
	}
}

以上就是一个简单的观察者模式实例。但是存在一个问题,那就是只要小孩一开始哭,那所有的观察者都要去进行处理。如果父母是分工明确的,孩子白天哭了爸爸管,孩子晚上哭了妈妈管,那当前这种方式就无法满足,简言之就是当前这种方式还不够灵活。

我们可以把孩子触发观察者处理的事件的具体信息,传递给观察者,让他们来判断,这个事件是不是需要自己去进行处理。我们可以抽象一个孩子的事件,其中有一个属性就是是否发生在晚上。

public class ChildEvent {

	// 在晚上
	private boolean inNight;
	
	public ChildEvent(){}
	
	public ChildEvent(boolean inNight){
		this.inNight = inNight;
	}

	public boolean isInNight() {
		return inNight;
	}

	public void setInNight(boolean inNight) {
		this.inNight = inNight;
	}
}

那么观察者接口也需要调整,因为要把事件对象传递进来,对应的父母的实现也需要增加判断。

public interface Observer {
	
	void dealWith(ChildEvent event);
}

public class Dad implements Observer{

	@Override
	public void dealWith(ChildEvent event) {
		if(!event.isInNight()){
			System.out.println("Dad tell jokes");
		}
	}

}

public class Mom implements Observer {

	@Override
	public void dealWith(ChildEvent event) {
		if(event.isInNight()) {
			System.out.println("Mom feed...");
		}
	}

}

对应Child类的cry方法,也需要改变,这里我触发一个在晚上的事件。这样的话,就只有妈妈这个观察者会去执行具体的处理。

public class Child {
	
	private List<Observer> observers = new ArrayList<>();
	
	{
		observers.add(new Dad());
		observers.add(new Mom());
	}
	
	public void cry() {
		System.out.println("child is crying");
		ChildEvent event = new ChildEvent(true);
		for (Observer observer : observers) {
			observer.dealWith(event);
		}
	}

}

一般的话,对于事件这个类,其实也是可以进行抽象的,而且一般会在事件这个类中增加一个source属性,表示由哪个对象来触发的这个事件。就类似于JS中的event,比如click事件,在click方法内部调用event.target,就会得到一个触发这个click事件的DOM。

public class ChildEvent {

	// 在晚上
	private boolean inNight;
	
	private Child source;
	
	public ChildEvent(){}
	
	public ChildEvent(boolean inNight){
		this.inNight = inNight;
	}

        public ChildEvent(Child source){
		this.source = source;
	}

	public boolean isInNight() {
		return inNight;
	}

	public void setInNight(boolean inNight) {
		this.inNight = inNight;
	}

	public Child getSource() {
		return source;
	}

	public void setSource(Child source) {
		this.source = source;
	}
}

我这里的事件类叫做ChildEvent,所以我的source对象就直接写成了Child类型。如果事件也做了抽象的话,那么这个source一般是Object类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值