设计模式--观察者(Observer)

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)

设计模式--观察者(Observer)

标准实现

目标/被观察者(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

 

你可能感兴趣的:(observer)