设计模式(十七)Observer模式
在Observer模式中,当观察对象的状态发生变化时,会通知给观察者。Observer模式适用于根据对象状态进行相应处理的场景。
首先看一下示例程序的视图。
然后用实际代码来理解这种设计模式。
1 package bigjunoba.bjtu.observer; 2 3 public interface Observer { 4 5 public abstract void update(NumberGenerator generator); 6 }
Observer接口是用来表示“观察者”的接口。具体的观察者会实现这个接口。用于生成数值的NumberGenerator类会调用update方法。如果调用update方法,NumberGenerator类就会将“生成的数值发生了变化,请更新显示内容”的通知发送给Observer。
1 package bigjunoba.bjtu.observer; 2 3 import java.util.ArrayList; 4 import java.util.Iterator; 5 6 public abstract class NumberGenerator { 7 8 private ArrayList<Observer> observers = new ArrayList<>(); 9 10 public void addObserver(Observer observer) { 11 observers.add(observer); 12 } 13 14 public void deleteObserver(Observer observer) { 15 observers.remove(observer); 16 } 17 18 public void notifyObservers() { 19 Iterator<Observer> iterator = observers.iterator(); 20 while (iterator.hasNext()) { 21 Observer observer = (Observer) iterator.next(); 22 observer.update(this); 23 } 24 } 25 26 public abstract int getNumber(); 27 public abstract void excute(); 28 29 }
NumberGenerator类是用于生成数值的抽象类。生成数值的excute方法和获取数值的getNumber方法都是抽象方法,需要子类去实现。observers字段中保存有观察NumberGenerator的Observer们。notifyObservers方法会向所有的Observer发送通知,告诉他们“我生成的数值发生了变化,请更新显示内容”。该方法会调用每个Observer的update方法。
1 package bigjunoba.bjtu.observer; 2 3 import java.util.Random; 4 5 public class RandomNumberGenetor extends NumberGenerator { 6 7 private Random random = new Random(); 8 private int number; 9 10 @Override 11 public int getNumber() { 12 return number; 13 } 14 15 @Override 16 public void excute() { 17 for (int i = 0; i < 10; i++) { 18 number = random.nextInt(50); 19 notifyObservers(); 20 } 21 } 22 }
RandomNumberGenetor类是NumberGenerator的子类。excute方法会生成10个随机数,并通过notifyObservers方法把每次生成的结果通知给观察者。
1 package bigjunoba.bjtu.observer; 2 3 public class DigitObserver implements Observer { 4 5 @Override 6 public void update(NumberGenerator generator) { 7 System.out.println("DigitObserver:" + generator.getNumber()); 8 try { 9 Thread.sleep(100); 10 } catch (InterruptedException e) { 11 } 12 } 13 }
DigitObserver类作为第一个观察者,它的功能是以数字形式显示观察到的数值。为了能看清它是如何显示数值的,使用Thread.sleep(100)来降低程序的运行速度。
1 package bigjunoba.bjtu.observer; 2 3 public class GraphObserver implements Observer { 4 5 @Override 6 public void update(NumberGenerator generator) { 7 System.out.println("GraphObserver:"); 8 9 int count = generator.getNumber(); 10 for (int i = 0; i < count; i++) { 11 System.out.print("*"); 12 } 13 14 System.out.println(""); 15 16 try { 17 Thread.sleep(100); 18 } catch (InterruptedException e) { 19 } 20 } 21 }
GraphObserver类作为第二个观察者,功能是将观察到的数值以****表示出来。
1 package bigjunoba.bjtu.observer; 2 3 public class Main { 4 public static void main(String[] args) { 5 NumberGenerator generator = new RandomNumberGenetor(); 6 Observer observer1 = new DigitObserver(); 7 Observer observer2 = new GraphObserver(); 8 generator.addObserver(observer1); 9 generator.addObserver(observer2); 10 generator.excute(); 11 } 12 }
Main类作为测试类。首先生成了RandomNumberGenerator类的实例保存在NumberGenerator类的generator字段中,然后生成两个观察者实例,然后将观察者注册之后,调用每一个观察者的update方法。
DigitObserver:20 GraphObserver: ******************** DigitObserver:46 GraphObserver: ********************************************** DigitObserver:10 GraphObserver: ********** DigitObserver:45 GraphObserver: ********************************************* DigitObserver:10 GraphObserver: ********** DigitObserver:5 GraphObserver: ***** DigitObserver:37 GraphObserver: ************************************* DigitObserver:24 GraphObserver: ************************ DigitObserver:34 GraphObserver: ********************************** DigitObserver:30 GraphObserver: ******************************
测试结果如上图所示。
这里不作过多解释。因为这种设计模式还是很容易理解的。