《Design Patterns》Observer.积跬步系列

Observer:观察者模式

先代码

该文章代码主要分三个版本:观察者原理实现版本、基于原理实现改进版本、Java实现版本。接下来一次做代码展示:
原理基本实现版本:

package h.l.demo.observer.explain;

import java.util.ArrayList;
import java.util.List;

/**
 * 
 * @author: Is-Me-Hl
 * @date: 2020年2月25日
 * @Description: 主题类/抽象通知者、发布者
 */
public class Subject {
	// 订阅者集合
	private List<Observer> observes = new ArrayList<>();

	// 添加订阅者
	public void addObserve(Observer observer) {
		observes.add(observer);
	}

	// 移除订阅者
	public void removeObserver(Observer observer) {
		observes.remove(observer);
	}

	// 通知所有的订阅者,即发布消息
	public void notifyObservers(Object arg) {
		for (Observer observer : observes) {
			observer.update(this,arg);
		}
	}
}
package h.l.demo.observer.explain;

/**
 * 
 * @author: Is-Me-Hl
 * @date: 2020年2月25日
 * @Description: 抽象观察者
 */
public abstract class Observer {
	public abstract void update(Subject subject, Object arg);
}

class Observer1 extends Observer {

	@Override
	public void update(Subject subject, Object arg) {
		System.out.println(this.getClass().getName()+":发布者:" + subject + ";发布消息:" + arg);
	}

}
class Observer2 extends Observer {

	@Override
	public void update(Subject subject, Object arg) {
		System.out.println(this.getClass().getName()+":发布者:" + subject + ";发布消息:" + arg);
	}

}

测试:

package h.l.demo.observer.explain;

/**
 * 
 * @author: Is-Me-Hl
 * @date: 2020年1月31日
 * @Description: 测试
 */
public class TestMainEnter {

	public static void main(String[] args) {
		Subject subject = new Subject();
		subject.addObserve(new Observer1());
		subject.addObserve(new Observer2());

		subject.notifyObservers(null);
		System.out.println("-----------------");
		subject.notifyObservers("Is-Me-HL,Fighting!!!");
	}

}

测试结果:
在这里插入图片描述


基于原理实现的改进版:使用反射+事件委托,解除在抽象类中发布者和订阅者之间的耦合:

package h.l.demo.observer.explain_improved_version;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Observer {

	// 订阅者/观察者
	private Object object;
	// 订阅者/观察者 被调用的方法名
	private String methodName;
	// 订阅者/观察者方法调用的参数
	private Object[] args;
	// 方法调用传入参数,其每个参数对应的数据类型
	private Class<?>[] argsTypes;

	public Observer(Object object, String methodName, Object... args) {
		this.object = object;
		this.methodName = methodName;
		this.args = args;
		if (this.args != null) {
			getArgsTypes(this.args);
		}
	}

	private void getArgsTypes(Object[] args) {
		this.argsTypes = new Class[args.length + 1];
		this.argsTypes[0] = new Object().getClass();
		for (int i = 1; i <= args.length; i++) {
			this.argsTypes[i] = args[i - 1].getClass();
		}
	}

	public void invoke(Object publishContext) throws NoSuchMethodException,
			SecurityException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException {
		// 判断方法是否存在
		Method method = this.object.getClass().getMethod(this.methodName,
				this.argsTypes);
		// 执行方法
		Object[] newObjectArr = new Object[this.args.length + 1];
		newObjectArr[0] = publishContext;
		for (int i = 1; i <= this.args.length; i++) {
			newObjectArr[i] = this.args[i - 1];
		}
		method.invoke(this.object, newObjectArr);
	}
}

class Observer1 {
	public void observer1Update(Object publishContext, String arg) {
		System.out.println("SubjectContext:" + publishContext + ";"
				+ this.getClass().getName() + ";发布消息:" + arg);
	}

}

class Observer2 {
	public void observer2Update(Object publishContext, String arg) {
		System.out.println("SubjectContext:" + publishContext + ";"
				+ this.getClass().getName() + ";发布消息:" + arg);
	}

}

这里要注意的是Observer类实际上就不在是观察者/订阅者类了,只是直接延用了这个类名,但改变了他的性质,实际上这个类目前的作用就是通过对客户端传进来的参数,实例化出具体的观察者,在指定方法中通过invoke方法代替具体观察类执行指定的方法。

package h.l.demo.observer.explain_improved_version;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

/**
 * 
 * @author: Is-Me-Hl
 * @date: 2020年2月25日
 * @Description: 主题类/抽象通知者、发布者
 */
public class Subject {
	// 订阅者集合
	private List<Observer> observes = new ArrayList<>();

	// 添加订阅者
	public void addObserve(Observer observer) {
		observes.add(observer);
	}

	// 移除订阅者
	public void removeObserver(Observer observer) {
		observes.remove(observer);
	}

	// 通知所有的订阅者,即发布消息
	public void notifyObservers(Object arg) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		for (Observer observer : observes) {
			observer.invoke(arg);
		}
	}
}

测试:

package h.l.demo.observer.explain_improved_version;

import java.lang.reflect.InvocationTargetException;

/**
 * 
 * @author: Is-Me-Hl
 * @date: 2020年1月31日
 * @Description: 测试
 */
public class TestMainEnter {

	public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Subject subject = new Subject();
		subject.addObserve(new Observer(new Observer1(), "observer1Update", "hello,observer1Update"));
		subject.addObserve(new Observer(new Observer2(), "observer2Update", "hello,observer2Update"));
		subject.notifyObservers("I am subject,是我给你们发布的通知");
		System.out.println("---------------");
		subject.notifyObservers(null);
		System.out.println("---------------");
		Subject subject2 = new Subject();
		subject2.addObserve(new Observer(new Observer1(), "observer1Update", ""));
		subject2.addObserve(new Observer(new Observer2(), "observer2Update", ""));
		subject2.notifyObservers(null);
	}
}

测试结果:
在这里插入图片描述


观察者模式Java实现版本:

package h.l.demo.observer.javaimpl;

import java.util.Observable;
/**
 * 
 * @author: Is-Me-Hl
 * @date: 2020年2月25日
 * @Description: 被观察者/发布者
 */
public class MyObservable extends Observable {

	public static void main(String[] args) {
		MyObservable myObservable = new MyObservable();
		myObservable.addObserver(new MyObserve1());
		myObservable.addObserver(new MyObserve2());
		
		// 发布消息
		myObservable.setChanged();
		myObservable.notifyObservers();
		
		// 发布带参数的消息
		myObservable.setChanged();
		myObservable.notifyObservers("我是发布者,我现在通知你们");
		
	}

}
package h.l.demo.observer.javaimpl;

import java.util.Observable;
import java.util.Observer;

/**
 * 
 * @author: Is-Me-Hl
 * @date: 2020年2月25日
 * @Description: 观察者模式也称为“发布订阅模式”。观察者类1:相当于“发布-订阅”说法中的订阅者
 */
public class MyObserve1 implements Observer {

	@Override
	public void update(Observable o, Object arg) {
		System.out.println("观察对象(订阅对象)" + this.getClass().getName() + ";");
		System.out.println("被观察对象(发布对象为):" + o + ",传递的参数为:" + arg);
	}

}
package h.l.demo.observer.javaimpl;

import java.util.Observable;
import java.util.Observer;

/**
 * 
 * @author: Is-Me-Hl
 * @date: 2020年2月25日
 * @Description: 观察者模式也称为“发布订阅模式”。观察者类2:相当于“发布-订阅”说法中的订阅者
 */
public class MyObserve2 implements Observer {

	@Override
	public void update(Observable o, Object arg) {
		System.out.println("观察对象(订阅对象)" + this.getClass().getName() + ";");
		System.out.println("被观察对象(发布对象为):" + o + ",传递的参数为:" + arg);
	}

}

实际上,跟踪Observable 类的代码,会发现和上面第一种原理基本实现的方法是一样的。Java给我们提供了这样的方法。观察者和被观察者类的耦合度是有的,如果要改进,可以使用委托的形式。
测试结果:
在这里插入图片描述

后分析

  • 个人建议:写代码是件幸福的事,So,do it

观察者模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生改变时,会通知所有观察者对象,使他们能自动更新自己。什么时候用观察者模式呢?当一个对象的改变需要同时改变其他对象的时候,并且其他对象的数据情况不知道的情况下。其实观察者模式在生活中有很多的例子:比如说录音机,你收听了哪个频道,一旦频道有内容发布了,你就能听到。比如天气预报,一旦天气改变了就会将这个变更通知到大家,大家多穿衣服或者少穿衣服,等等。总结就是,N个观察者订阅,1个被观察者发布,当然这里的观察者和被观察者是指的角色,角色关系是N:1,事实上这个被观察者的1是个抽象,具体通知观察者的人或许是X,亦或许是Y。

其他例子:参考《大话设计模式》老板回来,前台负责通知员工关闭股票、关闭NBA


注:以上文章仅是个人总结,若有不当之处,望不吝赐教

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值