GOF给出的定义:
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
定义了对象之间的一种一对多的依赖关系,这样,当一个对象的状态发生变化时,所有的依赖对象都被通知并自动更新。
包含观察者与被观察者(也称为主题)
使用场景:
1、有两个抽象类型相互依赖。将他们封装在各自的对象中,就可以对它们单独进行改变和复用。
2、对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变。
3、一个对象必须通知其他对象,而它又不需知道其他对象是什么。
观察这模式的结构(UML)
标准实现:
目标/被观察者(Subject) 在这里对观察者进行添加和删除操作,并通知观察者
1 /** 2 * 被观察者对象(目标/主题对象),注册和删除观察者的接口 3 * 4 * @author blacksonny 5 * @since 2015年7月1日 6 */ 7 public class Subject { 8 9 //保存注册的观察者对象 10 private List<Observer> observers = new ArrayList<Observer>(); 11 12 //Attach observer 13 public void attach(Observer o){ 14 observers.add(o); 15 } 16 17 //Delete observer 18 public void detach(Observer o){ 19 observers.remove(o); 20 } 21 22 //Notify all observer who has register 23 protected void notifyObservers(){ 24 for (Observer observer : observers) { 25 observer.update(this); 26 } 27 } 28 }
观察者(Observer) 单目标对象发生变化时,通知这个对象
1 /** 2 * 观察者抽象接口,当目标对象发生改变时,通知这个对象 3 * 4 * @author blacksonny 5 * @since 2015年7月1日 6 */ 7 public interface Observer { 8 9 /** 10 * 更新观察者 11 * 12 * @param subject 13 * 被观察者对象,方便获取被观察者状态 14 */ 15 void update(Subject subject); 16 }
具体目标对象(ConcreteSubject) 继承Subject,在这里改变自身状态并通知观察者
1 /** 2 * 具体的被观察者对象 3 * 4 * @author blacksonny 5 * @since 2015年7月1日 6 */ 7 public class ConcreteSubject extends Subject { 8 9 // 被观察者对象的状态 10 private String subjectState; 11 12 public String getSubjectState() { 13 return subjectState; 14 } 15 16 public void setSubjectState(String subjectState) { 17 this.subjectState = subjectState; 18 this.notifyObservers();//状态发生变化,通知观察者 19 } 20 21 }
观察者实现(ConcreteObserver) 接收被观察者(目标对象)消息,两者状态保持一致
1 /** 2 * 具体的观察者对象,实现更新的方法,使自身的状态和被观察者对象状态保持一致 3 * 4 * @author blacksonny 5 * @since 2015年7月1日 6 */ 7 public class ConcreteObserver implements Observer { 8 // 观察者对象状态 9 private String observerState; 10 11 @Override 12 public void update(Subject subject) { 13 observerState = ((ConcreteSubject) subject).getSubjectState(); 14 15 } 16 17 }
JAVA自身提供的Observer模型
SalaryConreteSubject被观察者实现,继承自JAVA提供的Observable被观察者
观察者模式对消息的通知分为推、拉两种,推模式由subject发起,通知对象可以相对单一;拉模式由observer主动获取。拉模式就需要subject发送自身对象,而推模式可以是一个简单的数据类型,建议采用拉模式,易扩展。
具体到代码中如下的标注的推方法主动传递一个消息内容 this.notifyObservers(salaryContent); 拉方法则无需传递参数,默认传递this对象 this.notifyObservers();
1 /** 2 * 继承自jdk的被观察者 3 * 4 * @author blacksonny 5 * @since 2015年7月1日 6 */ 7 public class SalaryConreteSubject extends Observable { 8 9 private String salaryContent; 10 11 public String getSalaryContent() { 12 return salaryContent; 13 } 14 15 public void setSalaryContent(String salaryContent) { 16 this.salaryContent = salaryContent; 17 //必须调用 18 this.setChanged(); 19 20 //推模式 21 this.notifyObservers(salaryContent); 22 23 //拉模式 24 this.notifyObservers(); 25 } 26 }
Employee具体观察者, 实现Observer接口,并实现update方法,而其中的两个参数,第一个就是拉模式的参数,第二个为退模式参数
1 /** 2 * 实现java.util.Observer 3 * 4 * @author blacksonny 5 * @since 2015年7月1日 6 */ 7 public class Employee implements Observer { 8 9 @Override 10 public void update(Observable o, Object arg) { 11 System.out.println("本月发放工资情况 拉过来:" + ((SalaryConreteSubject) o).getSalaryContent()); 12 System.out.println("本月发放工资情况 推过来:" + arg); 13 } 14 }
Client测试:
1 /** 2 * 测试java提供的观察者模式 3 * 4 * @author blacksonny 5 * @since 2015年7月1日 6 */ 7 public class Client { 8 9 /** 10 * @param args 11 */ 12 public static void main(String[] args) { 13 14 // 创建被观察者对象 15 SalaryConreteSubject subject = new SalaryConreteSubject(); 16 17 // 创建观察者对象 18 Employee employee = new Employee(); 19 // 注册对象 20 subject.addObserver(employee); 21 22 subject.setSalaryContent("10k"); 23 } 24 }
输出结果
本月发放工资情况 拉过来:10k 本月发放工资情况 推过来:10k
时间: 2024-10-10 00:21:13