观察者模式手动实现与讲解

版权声明:本文为博主原创文章,转载请注明作者。 https://blog.csdn.net/a18792721831/article/details/81233593

观察者模式是经典设计模式中的一种,使用广泛。

观察者模式实现两个耦合度较高的类解耦。

观察者模式由观察者和被观察者组成;在实现中,被观察者为主体;在作用中,观察者为主体。(一般情况下)

观察者模式在现实中的场景可简单对应为:张三看见李四去吃饭了,张三也去吃饭了。

张三是观察者,李四是被观察者。

李四去吃饭,被观察者的状态改变;张三看见,被观察者广播通知观察者;张三也去吃饭了,执行观察者自身动作。

通过这个例子,可以理解到,被观察者需要作出三件事:

  1. 被观察者需要添加观察者到自身广播范围(张三需要能看见李四);
  2. 被观察者需要删除观察者从自身广播范围(张三有时候不要看李四去吃饭,可能不看他了);
  3. 被观察者需要进行广播通知范围内的观察者。

观察者就只需要做一件事:

当被通知时,执行自身的动作。

 

接下来是实现的一个小例子:

首先需要定义观察者和被观察者的行为(接口)

定义被观察者的接口IObservered

方法

addObserver(ObserveredPeople o)

modify(Object arg)

delObserver(ObserveredPeople o)

public interface IObservered {

	boolean addObserver(IObserver o);
	void modifyObserver(Object arg);
	boolean delObserver(IObserver o);
}

定义观察者的接口IObserver

方法update()

public interface IObserver {

	void update(ObserveredPeople o,Object arg);
}

定义被观察者的实现类

ObserveredPeople

public class ObserveredPeople implements IObservered{

	private boolean changed;//通知标志,true才通知
	private Vector vector;//观察者广播范围
	public void setChanged(){
		changed = true;
	}
	public ObserveredPeople(){
                //构造方法中进行实例化和初始化
		changed = false;
		vector = new Vector();
	}
	@Override
	public boolean addObserver(IObserver o) {
                //如果传入对象为空,或者广播范围内已存在
                //那么就会抛出空指针异常
                //可以在外层捕获这个异常
		if(o != null && !vector.contains(o)){
			vector.addElement(o);
			return true;
		}else{
			throw new NullPointerException("传入的观察者对象空");
		}
	}

	@Override
	public void modifyObserver(Object arg) {
                //如果有效,使用增强for语句循环调用update方法
		if(changed){
			for (Object o : vector) {
				if(o instanceof IObserver){
					((IObserver) o).update(this, arg);
				}
			}
		}
                changed = false;
	}

	@Override
	public boolean delObserver(IObserver o) {
		if(o != null &&  vector.contains(o)){
			vector.remove(o);
			return true;
		}else{
			throw new NullPointerException("传入的观察者不存在或者不在广播范围内");
		}
	}

}

以上这些类可以作为工具类存在,也就是说,在任何地方能够使用到观察者模式,这些都是相同的。

具体使用观察者实现观察者接口,被观察者继承被观察者类。

创建一个被观察者

//注意导包
public class ObserveredUsing extends ObserveredPeople{

	private String name;
	private int age;
	public ObserveredUsing(String name,int age){
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public void setData(Object arg){
		System.out.println("name:"+name+"  "+"age:"+age+"   "+"arg:"+arg.toString());
		modifyObserver(arg);
	}
}

创建2个观察者

//注意导包
public class ObserverUsingEat implements IObserver{

	private String name;
	private int age;
	public ObserverUsingEat(String name,int age){
		this.name = name;
		this.age = age;
	}
	@Override
	public void update(ObserveredPeople o, Object arg) {
		System.out.println("name:"+name+"  "+"age:"+age+"   "+"arg:"+arg.toString());
	}
	
}

第二个观察者

public class ObserverUsingPlay implements IObserver{

	private String name;
	private String play;
	public ObserverUsingPlay(String name,String play){
		this.name = name;
		this.play = play;
	}
	private void doPlay(){
		System.out.println("开始运动");
		System.out.println("name:"+name);
		System.out.print("   我做"+play+"运动");
	}
	@Override
	public void update(ObserveredPeople o, Object arg) {
		doPlay();
		System.out.println(arg.toString());
	}

}

主方法

public class Main {

	public static void main(String[] args) {
		/**
		 * 张三是被观察者
		 */
		ObserveredUsing zhangsan = new ObserveredUsing("张三",32);
		/**
		 * 李四,王五是观察者
		 * 当张三做出动作,李四王五会做出相应的动作
		 */
		ObserverUsingEat lisi = new ObserverUsingEat("李四",20);
		ObserverUsingEat wangwu = new ObserverUsingEat("王五",80);
		/**
		 * 添加到广播对象中
		 */
		ObserverUsingPlay no1 = new ObserverUsingPlay("1号", "跑步");
		ObserverUsingPlay no2 = new ObserverUsingPlay("2号", "跳");
		zhangsan.addObserver(lisi);
		zhangsan.addObserver(wangwu);
		zhangsan.addObserver(no1);
		zhangsan.addObserver(no2);
		zhangsan.setChanged();
		zhangsan.setData("吃饭");
	}

}

运行结果

name:张三  age:32   arg:吃饭
name:李四  age:20   arg:吃饭
name:王五  age:80   arg:吃饭
开始运动
name:1号
   我做跑步运动吃饭
开始运动
name:2号
   我做跳运动吃饭

这个代码和jdk实现的源码基本类似,但是jdk的是线程安全的,我们这个线程不安全。

使用观察者模式一般使用jdk的接口和类,非常容易使用。

但是自己写一次,理解更加深刻。

猜你喜欢

转载自blog.csdn.net/a18792721831/article/details/81233593
今日推荐