【设计模式】 观察者模式

接口意味着角色或者功能,一个类实现了一个接口就意味着这个类具有了某种功能,能够为外界提供这种功能。

从接口的角度来看,观察者模式有两种角色,observer和subject(被观察者)

二者之间的关系:主题具有某种状态,体现在代码中就是具有某些字段,这些字段是观察者所感兴趣的。一旦数据发生了改变,就应该让观察者得知,告诉观察者发生了改变。这就是观察者模式的大致概念。


程序中该如何实现?

要让主题持有对观察者的引用才能做到通知观察者,如果有多个观察者?那么主题中必须持有对观察者的引用的list才行。观察者要想对某一个主题感兴趣,就必须把自己注册到主题的list中。因此主题的接口中必须提供注册方法,相应的也要有解除方法。注册完成之后,一旦主题的数据改变,那么主题要能通知list中的观察者,因此也要有notify方法。

关于notify方法,可以在主题的业务方法(即可以改变主题数据的方法)中调用,但是这样notify用处了private method的感觉,不推荐。更好的是让主题的使用者调用,因为接口毕竟是要提供给别人使用的,如果只是在自己的类内调用,没有必要定义为public的。也就是说客户端调用subject.f()改变了数据,那么客户端还要调用subject.notify()来通知,而不是在f内部调用notify。

至于观察者呢?这个角色只要提供handle方法让主题调用即可。这个handle方法就是用来处理主题发生变化后的情况。


Subject接口:

package Subject;

import Observer.Observer;

public interface Subject {

	public void register(Observer observer);
	public void remove(Observer observer);
	public void notifyObr();

}

Observer接口:

package Observer;

public interface Observer {

	public void handle();
	
}
具体的主题Mouse类:

package Subject.Concrete;

import java.util.ArrayList;
import java.util.List;
import Observer.Observer;
import Subject.Subject;

public class Mouse implements Subject{

	private List<Observer> observers = new ArrayList<>();
	//鼠标x坐标
	private int x;
	//鼠标y坐标
	private int y;
	
	@Override
	public void register(Observer observer) {
		observers.add(observer);
	}

	@Override
	public void remove(Observer observer) {
		observers.remove(observer);		
	}

	@Override
	public void notifyObr() {
		for(Observer o : observers){
			o.handle();
		}
	}

	//业务方法,鼠标移动
	public void move(int x_inc, int y_inc){
		this.x = x + x_inc;
		this.y = y + y_inc;
		
		notifyObr();
	}
	
	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

}

具体的观察者类:

package Observer.Concrete;

import Observer.Observer;

public class MouseMoving implements Observer{

	@Override
	public void handle() {
		// TODO Auto-generated method stub
		System.out.println("mouse moves...");
	}

}
客户端:

package Test;

import Observer.Concrete.MouseMoving;
import Subject.Concrete.Mouse;

public class Test {

	
	public void test(){
		
		MouseMoving mouseMoving = new MouseMoving();
		Mouse mouse = new Mouse();
		mouse.register(mouseMoving);
		
		mouse.move(1, 1);
		mouse.notifyObr();
	}

}
结果:




总结:

1,观察者角色和主题角色

2,通知机制就是在主题里面加一个观察者的list


事件机制是程序设计中常用的机制,其实现可以基于观察者模式。主题角色不变,观察者角色变成了监听器角色,本质并没有什么大的改变。还加入了事件的概念,之前主题在通知观察者的时候,并没有传递任何参数给观察者,而事实上,观察者在处理变化的时候,需要得到变化的具体情况,可以把主题的具体变化封装在事件中,传递给观察者。

事件接口:

package Event;


public interface Event {

	public String getSource();
	public void setSource(String source);
}

鼠标事件:

package Event;


public class MouseEvent implements Event{

	private String source;
	@Override
	public String getSource() {
		return source;
	}
	@Override
	public void setSource(String source) {
		this.source = source;
	}

}
观察者接口:

package Observer;

import Event.Event;

public interface Observer {

	public void handle(Event event);
	
}
客户端:

package Test;

import Event.Event;
import Event.MouseEvent;
import Observer.Concrete.MouseMoving;
import Subject.Concrete.Mouse;

public class Test {

	
	public void test(){
		
		MouseMoving mouseMoving = new MouseMoving();
		Mouse mouse = new Mouse();
		mouse.register(mouseMoving);
		
		mouse.move(1, 1);
		String source = "1,1";
		Event event = new MouseEvent();
		event.setSource(source);
		mouse.notifyObr(event);
	}

}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值