觀察者模式詳解

觀察者模式是衆多軟件設計模式中的一種,又稱發佈訂閱模式.被觀察的對象發生了變化,觀察者對象們能夠第一時間收到通知,
並做出相應的處理,例如做爲一家餐館的會員,若餐館出了新品那麼會第一時間通知到各個會員,不是會員的路人則不會收到通知java

再看一下類圖:設計模式


 

 

 

 

 

 

 

 

FoodSubject sub = new FoodSubject();
	    new LisaObserver(sub);
	    Observer tom = new TomObserver(sub);
	    System.out.println("----菜品發佈------");
	    Thread.sleep(1000);
	    sub.onChange("剁椒魚頭", "80.00", "熱菜");
	    
	    System.out.println("--- tom居然取消關注  ---");
	    sub.remove(tom);
	    System.out.println("----又有菜品發佈哦------");
	    Thread.sleep(1000);
	    sub.onChange("外婆菜炒蛋", "18.00", "熱菜");
----菜品發佈------
我是lisa, 食物:剁椒魚頭,價格:80.00,菜品類型:熱菜
我是tom, 食物:剁椒魚頭,價格:80.00,菜品類型:熱菜
--- tom居然取消關注  ---
----又有菜品發佈哦------
我是lisa, 食物:外婆菜炒蛋,價格:18.00,菜品類型:熱菜

JDK已經幫咱們實現了觀察者模式,Observable至關於Subject,Observer同上自定義的Observer,只有一個方法:
//①.被觀察者對象,②.參數
 void update(Observable o, Object arg);ide

Observable是一個class而非一個接口
提供addObserver(Observer o)
deleteObserver(Observer o)測試

notifyObservers()
notifyObservers(Object arg)
//必須在調用notifyObservers方法前先調用一次
//由於只有爲true時纔會通知觀察者
void setChanged()this

public class News extends Observable{
	private String subject;
	private String content;
	private Date date;
	public News() {}
	public void onChange(String subject, String content){
		this.subject = subject;
		this.content = content;
		this.date = new Date();
		setChanged();
		notifyObservers();
	}
	
	public String getSubject() {
		return subject;
	}
	
	public String getContent() {
		return content;
	}
	
	public Date getDate() {
		return date;
	}
	
}


 

public class Person implements Observer, IShow {
	private News news;
	private String name;
	public Person(Observable subject, String name) {
		subject.addObserver(this);
		this.name = name;
	}

	@Override
	public void update(Observable o, Object arg) {
		if (o == null || !(o instanceof News)) {
			return;
		}
		news = (News) o;
		show();
	}

	@Override
	public void show() {
		System.out.println("我是" + name + ",我閱讀了:\n 主題:" + news.getSubject() + "\n內容:"
		        + news.getContent()
		        + "\n發佈時間:" + news.getDate());
	}

若是觀察者對象不須要全部的參數 設計

public class Lisa implements Observer, IShow{
	private News news;
	public Lisa(Observable subject) {
	    subject.addObserver(this);
    }
	@Override
	public void show() {
		System.out.println("我是lisa,我閱讀了最新的新聞:\n 主題:" + news.getSubject() + ",內容:"
		        + news.getContent());
	}

	@Override
    public void update(Observable o, Object arg) {
		if(o == null || !(o instanceof News)){
			return;
		}
		news = (News)o;
		show();
    }

 

public interface IShow {
	void show();
}
//測試
 News news = new News();
	    System.out.println("----- 新聞資訊 -------");
	    String subject = "生態養海 擁海而興";
	    String content = "進入11月下旬,海風吹在臉上已有些刺骨,但溫州洞頭區東屏街道東嶴村,漁家樂的生意依舊紅火。";
	    new Tom(news);
	    new Person(news,"any");
	    new Person(news,"tony");
	    new Person(news,"lexa");
	    Lisa lisa = new Lisa(news);
	    news.onChange(subject, content);
	    Thread.sleep(1000);
	    System.out.println("lisa不感興趣,取消關住.");
	    news.deleteObserver(lisa);
	    Thread.sleep(1000);
	    System.out.println("----- 又發佈了最新資訊 --------");
	    subject = "特朗普赦免感恩節火雞:它將擁有一個很是光明的將來";
	    content = "美國總統特朗普21日遵守白宮的節日傳統,在感恩節前赦免了兩隻火雞。";
	    news.onChange(subject, content);
----- 新聞資訊 -------
我是lisa,我閱讀了最新的新聞:
 主題:生態養海 擁海而興,內容:進入11月下旬,海風吹在臉上已有些刺骨,但溫州洞頭區東屏街道東嶴村,漁家樂的生意依舊紅火。
我是lexa,我閱讀了:
 主題:生態養海 擁海而興
內容:進入11月下旬,海風吹在臉上已有些刺骨,但溫州洞頭區東屏街道東嶴村,漁家樂的生意依舊紅火。
發佈時間:Thu Nov 23 16:53:16 CST 2017
我是tony,我閱讀了:
 主題:生態養海 擁海而興
內容:進入11月下旬,海風吹在臉上已有些刺骨,但溫州洞頭區東屏街道東嶴村,漁家樂的生意依舊紅火。
發佈時間:Thu Nov 23 16:53:16 CST 2017
我是any,我閱讀了:
 主題:生態養海 擁海而興
內容:進入11月下旬,海風吹在臉上已有些刺骨,但溫州洞頭區東屏街道東嶴村,漁家樂的生意依舊紅火。
發佈時間:Thu Nov 23 16:53:16 CST 2017
我是tom,我閱讀了:
 主題:生態養海 擁海而興,內容:進入11月下旬,海風吹在臉上已有些刺骨,但溫州洞頭區東屏街道東嶴村,漁家樂的生意依舊紅火。,發佈時間:Thu Nov 23 16:53:16 CST 2017
lisa不感興趣,取消關住.
----- 又發佈了最新資訊 --------
我是lexa,我閱讀了:
 主題:特朗普赦免感恩節火雞:它將擁有一個很是光明的將來
內容:美國總統特朗普21日遵守白宮的節日傳統,在感恩節前赦免了兩隻火雞。
發佈時間:Thu Nov 23 16:53:18 CST 2017
我是tony,我閱讀了:
 主題:特朗普赦免感恩節火雞:它將擁有一個很是光明的將來
內容:美國總統特朗普21日遵守白宮的節日傳統,在感恩節前赦免了兩隻火雞。
發佈時間:Thu Nov 23 16:53:18 CST 2017
我是any,我閱讀了:
 主題:特朗普赦免感恩節火雞:它將擁有一個很是光明的將來
內容:美國總統特朗普21日遵守白宮的節日傳統,在感恩節前赦免了兩隻火雞。
發佈時間:Thu Nov 23 16:53:18 CST 2017
我是tom,我閱讀了:
 主題:特朗普赦免感恩節火雞:它將擁有一個很是光明的將來,內容:美國總統特朗普21日遵守白宮的節日傳統,在感恩節前赦免了兩隻火雞。,發佈時間:Thu Nov 23 16:53:18 CST 2017

由於Observable是一個「類」,你必須設計一個類繼承它。若是某類想同時
具備Observable類和另外一個超類的行爲,就會陷入兩難,畢竟Java不支持多重繼承。
這限制了Observable的複用潛力.
再者,由於沒有Observable接口,因此沒法創建本身的實現和Java內置的
Observer搭配使用,也沒法將java.util的實現換成另外一套作法的實現(比方說,
若是你可以擴展java.util.Observable,那麼Observable「可能」能夠符合你的需求。
不然,你可能須要像本章開頭的作法那樣本身實現這一整套觀察者模式。
並且setChanged()方法被保護起來了(被定義成protected)。這意味着:除非你繼承自Observable,不然你沒法建立Observable實例並組合到你本身的對象中來。code

-------------------------orm

//幾種事件類型:server

/**
 * Created by Bellamy.xiao on 2018/3/20.
 */
public enum EventType {
	ADD("ADD invoke","add evnet"),
	REMOVE("remove invoke", "add evnet.");
	private String invoke;
	private String evnet;
	private EventType(String invoke, String evnet) {
	   this.invoke = invoke;
	   this.evnet = evnet;
    }
	public String getInvoke() {
		return invoke;
	}
	public void setInvoke(String invoke) {
		this.invoke = invoke;
	}
	public String getEvnet() {
		return evnet;
	}
	public void setEvnet(String evnet) {
		this.evnet = evnet;
	}
	
}
//Event
public class Event {
	private Object target;
	private Method callBack;
	private Date  callTime;
	private String detail;
	public Event(Object target, Method callBack) {
	    super();
	    this.target = target;
	    this.callBack = callBack;
    }
	public Event() {
    }
	
	public Event(Object target, Method callBack, Date callTime, String detail) {
	    super();
	    this.target = target;
	    this.callBack = callBack;
	    this.callTime = callTime;
	    this.detail = detail;
    }
	public Event(Object target, Method callBack,String detail) {
	    super();
	    this.target = target;
	    this.callBack = callBack;
	    this.detail = detail;
    }
	@Override
	public String toString() {
		return "Event [target=" + target + ", callBack=" + callBack + ", callTime="
		        + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(callTime)
		        + ", detail=" + detail + "]";
	}
	public Event(Object target, Method callBack, Date callTime) {
	    super();
	    this.target = target;
	    this.callBack = callBack;
	    this.callTime = callTime;
    }
	public Object getTarget() {
		return target;
	}
	public void setTarget(Object target) {
		this.target = target;
	}
	public Method getCallBack() {
		return callBack;
	}
	public void setCallBack(Method callBack) {
		this.callBack = callBack;
	}
	public Date getCallTime() {
		return callTime;
	}
	public void setCallTime(Date callTime) {
		this.callTime = callTime;
	}
	public String getDetail() {
		return detail;
	}
	public void setDetail(String detail) {
		this.detail = detail;
	}
	
	
}
//事件監聽
public class EventListener {
	private Map<EventType, Event> events = new HashMap<EventType, Event>();

	private void bind(Event e) {
		e.setCallTime(new Date());
		try {
			e.getCallBack().invoke(e.getTarget(), e);
		} catch (Exception ex) {
			ex.printStackTrace();
		}

	}

	public void bind(EventType type) {
		if (!this.events.containsKey(type)) {
            //這裏不在事件集合中的直接拋異常
			throw new RuntimeException(type.getEvnet() + ",unknown!");
		}

		this.bind(this.events.get(type));
	}

	public void addListener(EventType type, Object tagert, Method m) {
		events.put(type, new Event(tagert, m, type.getInvoke()));
	}

	public void removeListener(EventType type) {
		events.remove(type);
	}
}
//回調通知
public class Observer {
	public void advice(Event e){
		System.out.println(e);
	}
}
//測試代碼
public static void main(String[] args) throws Exception{
	    Method m = Observer.class.getMethod("advice",new Class[]{Event.class});
	    
	    EventListener listener = new EventListener();
	    listener.addListener(EventType.ADD, new Observer(), m);
	    listener.addListener(EventType.REMOVE, new Observer(), m);
	    listener.bind(EventType.ADD);
       //移除事件再綁定測試
	    listener.removeListener(EventType.ADD);
	    listener.bind(EventType.ADD);
	    
	    
    }

//console:對象

Event [target=Observer@25154f, callBack=public void Observer.advice(Event), callTime=2018-03-21 16:51:49, detail=ADD invoke]Exception in thread "main" 
java.lang.RuntimeException: add evnet,unknown!
	at EventListener.bind(EventListener.java:23)
	at TestObserver.main(TestObserver.java:22)
相關文章
相關標籤/搜索