1、前言java
觀察者模式其實最好的名稱應該是「發佈訂閱」模式,和咱們如今大數據之中的發佈訂閱方式比較相似,可是也有區別的地方,在上一個設計模式,咱們學習了仲裁者模式,其中當控件的狀態發生改變的時候就會向仲裁者發出信息,讓仲裁者進行仲裁,這其實和發佈訂閱很是的相似,可是用處是不同的,仲裁者模式是用來解除複雜對象之間的相互調用的關係,從而獨立出來進行開發,而觀察者模式是在被觀察者狀態改變的時候被動的被喚醒進行相應的處理,二者的實現比較相似,好比都是被動喚醒的,可是思想和用處是不同的,被喚醒以後的處理是不同的。git
2、代碼編程
首先咱們本身實現觀察者模式,其次咱們使用java已經實現好的觀察者接口,而後來對比一下二者的不一樣。設計模式
(一)、本身實現觀察者模式dom
package zyr.dp.observer; import java.util.ArrayList; import java.util.Iterator; public abstract class NumberGenerator { private ArrayList observers=new ArrayList(); public void add(Observer observer){ observers.add(observer); } public void remove(Observer observer){ observers.remove(observer); } public void notifyObserver(){ Iterator it=observers.iterator(); while(it.hasNext()){ Observer object=(Observer)it.next(); object.update(this); } } public abstract void execuate(); public abstract int getNumber(); }
package zyr.dp.observer; import java.util.Random; public class RandomNumberGenerator extends NumberGenerator { private Random random=new Random(); private int number; public int getNumber(){ return number; } public void execuate() { for(int i=0;i<20;i++){ number=random.nextInt(60); notifyObserver(); } } }
package zyr.dp.observer; public interface Observer { public abstract void update(NumberGenerator object); }
package zyr.dp.observer; public class DigitalObserver implements Observer { public void update(NumberGenerator object) { System.out.println("DigitalObserver:"+object.getNumber()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }
package zyr.dp.observer; public class GraphObserver implements Observer { public void update(NumberGenerator object) { System.out.print("GraphObserver:"); for(int i=0;i<object.getNumber();i++){ System.out.print("*"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(); } }
package zyr.dp.observer; public class Main { public static void main(String[] args) { NumberGenerator numberGenerator=new RandomNumberGenerator(); numberGenerator.add(new DigitalObserver()); numberGenerator.add(new GraphObserver()); numberGenerator.execuate(); } }
由此能夠看到當被觀察者的狀態發生改變的時候會主動通知觀察者,使用notifyObserver的方法將本身的狀態傳遞過去,由於是本身定義的被觀察者的抽象類以及接口,所以使用起來很是的方便,代碼也不是不少,可以按照本身的要求來完成更新操做,對比與仲裁者模式,被觀察者是主動將本身的內容傳遞給觀察者的,而仲裁者模式中,組員是自己就已經組合進了仲裁者之中,這也是一點不一樣。代碼比較簡單,這裏被觀察者使用了抽象類而不使用接口的緣由是須要定義對觀察者對象的委託,所以使用了抽象類,而觀察者只用了update方法將被觀察者經過參數傳遞的方式委託進來,所以使用接口更加清晰一點,固然抽象類也能夠,只不過能使用接口的就不要使用抽象類,由於一個類只能繼承一個父類,可是能夠實現不少接口。組件化
(二)、使用java自帶的觀察者模式學習
package zyr.dp.java; import java.util.Observable; import java.util.Random; public class RandomNumberGenerator extends Observable { private Random random=new Random(); private int number; public int getNumber(){ return number; } public void execuate() { for(int i=0;i<20;i++){ number=random.nextInt(60); setChanged(); notifyObservers(); } } }
package zyr.dp.java; import java.util.Observable; import java.util.Observer; public class DigitalObserver implements Observer { public void update(Observable object, Object arg) { System.out.println("DigitalObserver爲:"+((RandomNumberGenerator)object).getNumber()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }
package zyr.dp.java; import java.util.Observable; import java.util.Observer; public class GraphObserver implements Observer { public void update(Observable object, Object arg) { System.out.print("GraphObserver爲:"); for(int i=0;i<((RandomNumberGenerator)object).getNumber();i++){ System.out.print("*"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(); } }
package zyr.dp.java; import java.util.Observable; public class Main { public static void main(String[] args) { Observable observable=new RandomNumberGenerator(); observable.addObserver(new DigitalObserver()); observable.addObserver(new GraphObserver()); ((RandomNumberGenerator)observable).execuate(); } }
能夠看到在java自定義的觀察者模式中,首先要修改setChanged();來使notifyObservers生效,其次,傳遞的參數不是很靈活,須要強制轉換成咱們想要的東西,最後在使用的時候也須要強制轉換,這是比較麻煩的,而且被觀察者也是繼承了抽象類Observable,不方便之後功能的擴展,若是之後再想繼承其它的類就很麻煩了。咱們本身設計的時候,可使用某些方式把抽象類變成接口,不過也須要必定的操做。大數據
3、總結this
經過觀察者模式使得觀察者和被觀察者之間面向抽象編程,觀察者不用知道本身觀察的對象究竟是誰的實例,只須要知道這個對象繼承了被觀察者的抽象類,所以當被觀察者增長的時候,觀察者能夠不用修改。一樣的,對於被觀察者的實例來講,並不須要知道本身究竟是唄哪個觀察者觀察了,只須要知道觀察本身的觀察者確定使用了觀察者的接口,所以觀察者和被觀察者之間經過面向抽象編程提升了可擴展性,便於組件化。spa
咱們能夠看到在面向對象編程中可以使用委託的就不要使用繼承,委託是弱關聯,繼承是強關聯。而且將一些共同操做抽象出來放到抽象類之中去定義,在參數傳遞中不使用具體類型而是用接口或者抽象類,這樣的設計思想便於組件化,具備可替代性。