设计模式之观察者模式
观察者模式我消化了两天,因为智商问题,理解的比较慢。。。另外恭喜我自己以科目二一百分的成绩顺利拿上驾照
言归正传,先从大神那里扒一张图,对着图看比较容易理解。
(图片来自左潇龙大佬,本图片仅供仅供学习使用,希望大佬不要怪罪)
观察者模式又称为发布订阅模式,这个模式由被观察者、观察者组成,他们的关系是观察者观察被观察者,当被观察者的状态发生改变的时候会通知对应的观察者。
简单点概括成通俗的话来说,就是一个类管理着所有依赖于它的观察者类,并且它状态变化时会主动给这些依赖它的类发出通知。
JDK中提供了观察者模式现成的代码,贴出来说明一下。
1 package java.util; 2 3 /** 4 * A class can implement the <code>Observer</code> interface when it 5 * wants to be informed of changes in observable objects. 6 *上面这句话翻译过来就是,当observable对象做出改变时,希望收到信息的类必须实现此接 7 * 口 8 * 9 */ 10 public interface Observer {//观察者 11 //当observable对象状态改变时必须要调用此方法通知实现此接口的对象 12 void update(Observable o, Object arg); 13 } 14 15 16 package java.util; 17 18 19 public class Observable {//被观察者 20 private boolean changed = false; 21 private Vector<Observer> obs;//用来管理观察者的集合 怕线程不安全使用vector 22 23 /** Construct an Observable with zero Observers. */ 24 25 public Observable() { 26 obs = new Vector<>(); 27 } 28 29 //添加观察者 30 public synchronized void addObserver(Observer o) { 31 if (o == null) 32 throw new NullPointerException(); 33 if (!obs.contains(o)) { 34 obs.addElement(o); 35 } 36 } 37 38 39 public synchronized void deleteObserver(Observer o) { 40 obs.removeElement(o); 41 } 42 43 44 //通知观察者 45 public void notifyObservers() { 46 notifyObservers(null); 47 } 48 49 50 public void notifyObservers(Object arg) { 51 52 Object[] arrLocal; 53 54 synchronized (this) { 55 56 if (!changed)//当被观察者状态没被改变 则终止此方法 57 return; 58 arrLocal = obs.toArray(); 59 clearChanged(); 60 } 61 62 for (int i = arrLocal.length-1; i>=0; i--) 63 ((Observer)arrLocal[i]).update(this, arg);//通知被观察者 64 } 65 66 67 public synchronized void deleteObservers() { 68 obs.removeAllElements(); 69 } 70 71 //改变被观察者状态 72 protected synchronized void setChanged() { 73 changed = true; 74 } 75 76 77 protected synchronized void clearChanged() { 78 changed = false; 79 } 80 81 82 public synchronized boolean hasChanged() { 83 return changed; 84 } 85 86 87 public synchronized int countObservers() { 88 return obs.size(); 89 } 90 }
用前些日子比较火的直播网站来举个例子,主播就是被观察者,观众则是观察者,观众们可以点击关注自己喜欢的主播(这里这个关注的动作就是观察者模式中的观察),当主播上线开始直播的时候,网站一般会通知观众们(通知)。以上场景用代码实现如下:
首先我们需要个主播,主播有自己的名字和直播的游戏,还有一个直播打游戏的方法。
1 package com.java.pubsub; 2 3 import java.util.Observable; 4 5 public class Player extends Observable{ 6 7 public Player(String name){ 8 this.name = name; 9 PlayerManage.getInstance().register(this); 10 } 11 12 public void play(){ 13 String title = "开播了,先"+this.game+"再吃鸡"; 14 this.setChanged(); 15 this.notifyObservers(title); 16 } 17 18 private String name; 19 private String game; 20 public String getName() { 21 return name; 22 } 23 public void setName(String name) { 24 this.name = name; 25 } 26 public String getGame() { 27 return game; 28 } 29 public void setGame(String game) { 30 this.game = game; 31 } 32 33 34 35 }
然后是我们的观众,我们的观众有关注主播和取消关注的两个方法之外,还有个提示主播上线打游戏的方法
1 package com.java.pubsub; 2 3 import java.util.Observable; 4 import java.util.Observer; 5 6 public class Viewer1 implements Observer{ 7 8 public void subscribe(String playerName){ 9 Player player = PlayerManage.getInstance().get(playerName); 10 if(player!=null){ 11 player.addObserver(this); 12 } 13 } 14 15 public void unsubscribe(String playerName){ 16 Player player = PlayerManage.getInstance().get(playerName); 17 if(player!=null){ 18 player.deleteObserver(this); 19 } 20 } 21 22 23 @Override 24 public void update(Observable o, Object arg) { 25 String title = (String) arg; 26 if(o instanceof Player){ 27 Player player = (Player) o; 28 System.out.println("收到推送=="+player.getName()+":"+title); 29 System.out.println("我去看"+player.getName()+"直播"+player.getGame()+"游戏"); 30 } 31 } 32 33 }
在主播的代码和观众的代码中出现了个PlayerManage,主播那么多当然有个超管来管管了。。超管会在主播上线或者注册的时候开始管理主播(添加和获取),在主播播放不良内容后也可以封停主播(remove)
1 package com.java.pubsub; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 public class PlayerManage { 7 8 private Map<String,Player> playerMap = new <String,Player>HashMap(); 9 10 public void register(Player player){ 11 playerMap.put(player.getName(), player); 12 } 13 14 public Player get(String playerName){ 15 return playerMap.get(playerName); 16 } 17 18 public void remove(Player player){ 19 playerMap.remove(player.getName()); 20 } 21 22 private PlayerManage(){} 23 24 public static PlayerManage getInstance(){ 25 return PlayerManageInstance.manage; 26 } 27 28 private static class PlayerManageInstance{//全站只有一个超管- - ! 29 private static PlayerManage manage=new PlayerManage(); 30 } 31 }
我们测试一下
1 package com.java.pubsub; 2 3 import java.util.Observable; 4 5 public class Test { 6 public static void main(String[] args) { 7 Player player=new Player("张三"); 8 player.setGame("CS:GO"); 9 10 Viewer1 viewer1=new Viewer1(); 11 viewer1.subscribe("张三"); 12 13 player.play(); 14 15 } 16 }
结果为:
观察者模式分离了观察者和被观察者二者的责任,这样让类之间各自维护自己的功能,专注于自己的功能,会提高系统的可维护性和可重用性。
总结一下,定义:观察者模式(有时又被称为发布-订阅模式、模型-视图模式、源-收听者模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实作事件处理系统。