天天看點

【設計模式】觀察者模式的實作及Java中的觀察者模式--------Java

觀察者模式(Observer):

一種通知依賴關系:一個對象的狀态發生改變,所有的依賴對象(觀察者對象)都将得到通知。

這種依賴關系過于緊密,為了将這種依賴關系弱化,松耦合,有了觀察者模式。

1.問題引入:

同僚上班炒股票,老闆回來的時候前台通知同僚停止。

package computer;

import java.util.ArrayList;

public class Test {
	public static void main(String[] args) {
		//前台童子喆
		Secretary tongzizhe=new Secretary();
		
		//兩個同僚,(同時設定名字及負責的前台)
		StockObserver tongshi1=new StockObserver("魏關侘", tongzizhe);
		StockObserver tongshi2=new StockObserver("易家揚", tongzizhe);
		
		//前台記下負責的同僚
		tongzizhe.Attach(tongshi1);
		tongzizhe.Attach(tongshi2);
		
		//發現老闆回來了
		tongzizhe.setAction("老闆回來了!");
		//通知兩個同僚
		tongzizhe.Notify();
	}
}

//前台秘書類(前台類依賴同僚類)
class Secretary{
	//前台負責的同僚
	private ArrayList<StockObserver> observers=new ArrayList<StockObserver>();
	
	//用字元串來表示目前老闆回來與否
	private String action;
	
	//添加同僚
	public void Attach(StockObserver observer) {
		observers.add(observer);
	}
	
	//通知同僚們
	public void Notify() {
		for(int i=0;i<observers.size();i++) {
			observers.get(i).update();
		}
	}

	public String getAction() {
		return action;
	}

	public void setAction(String action) {
		this.action = action;
	}
	
}

//同僚類(同僚類依賴前台類)
class StockObserver{
	//同僚姓名
	private String name;
	
	//給同僚報信的前台
	private Secretary sub;

	//構造函數設定姓名和相關的前台
	public StockObserver(String name, Secretary sub) {
		this.name = name;
		this.sub = sub;
	}
	
	//得到前台的通知,采取行動
	public void update() {
		System.out.println(sub.getAction()+name+",關閉股票行情,繼續工作!");
	}
}
           

缺點:不符合開放封閉原則。

2.改進:

根據依賴倒轉原則,依賴于抽象,而不是互相依賴。

package computer;

import java.util.ArrayList;

public class Test {
	public static void main(String[] args) {
		//前台
		Secretary tongzizhe=new Secretary();
		
		//看股票的同僚
		StockObserver tongshi1=new StockObserver("薇薇",tongzizhe);
		//看NBA的同僚
		NBAObserver tongshi2=new NBAObserver("熠熠",tongzizhe);
		
		tongzizhe.attach(tongshi1);
		tongzizhe.attach(tongshi2);
		
		tongzizhe.setAction("老闆回來了!");
		tongzizhe.Notify();
	}
}

//抽象通知者
abstract class Subject{
	
	//老闆的狀态
	private String action;
	
	//添加觀察者的方法
	abstract void attach(Observer observer);
	//删除觀察者的方法
	abstract void detach(Observer observer);
	
	//通知觀察者
	abstract void Notify();
	
	//設定擷取老闆狀态
	public String getAction() {
		return action;
	}
	public void setAction(String action) {
		this.action = action;
	}
}

//具體通知者(老闆)
class Boss extends Subject{
	//同僚清單
	private ArrayList<Observer> observers=new ArrayList<Observer>();

	//添加觀察者
	void attach(Observer observer) {
		observers.add(observer);
	}

	//删除觀察者
	void detach(Observer observer) {
		observers.remove(observer);
	}

	//通知觀察者
	void Notify() {
		for(int i=0;i<observers.size();i++) {
			observers.get(i).update();
		}
	}
}

//具體通知者(前台秘書類)
class Secretary extends Subject{
	//同僚清單
	private ArrayList<Observer> observers=new ArrayList<Observer>();

	//添加觀察者
	void attach(Observer observer) {
		observers.add(observer);
	}

	//删除觀察者
	void detach(Observer observer) {
		observers.remove(observer);
	}

	//通知觀察者
	void Notify() {
		for(int i=0;i<observers.size();i++) {
			observers.get(i).update();
		}
	}
}

//抽象觀察者
abstract class Observer{
	//觀察者姓名
	protected String name;
	
	//通知者(抽象的)
	protected Subject sub;
	
	//構造函數(設定觀察者姓名和通知者)
	public Observer(String name, Subject sub) {
		this.name = name;
		this.sub = sub;
	}
	
	//做出行動
	public abstract void update();
}

//看股票的同僚(具體觀察者)
class StockObserver extends Observer{

	public StockObserver(String name, Subject sub) {
		super(name, sub);
	}

	//做出行動
	public void update() {
		System.out.println(sub.getAction()+name+",關閉股票行情,繼續工作!");
	}
}

//看NBA的同僚(具體觀察者)
class NBAObserver extends Observer{

	public NBAObserver(String name, Subject sub) {
		super(name, sub);
	}

	//做出行動
	public void update() {
		System.out.println(sub.getAction()+name+",關閉NBA直播,繼續工作!");
	}
}
           

觀察者模式适用于:一個對象的狀态發生變化的時候,某些其他的對象能做出相應的改變。且耦合度較低。

3.觀察者模式:

package computer;

import java.util.ArrayList;

public class Test {
	public static void main(String[] args) {
		//具體的觀察者
		ConcreteSubject s=new ConcreteSubject();
		
		//具體的被觀察者
		ConcreteObserver c1=new ConcreteObserver("X",s);
		ConcreteObserver c2=new ConcreteObserver("Y",s);
		ConcreteObserver c3=new ConcreteObserver("Z",s);
		
		s.attach(c1);
		s.attach(c2);
		s.attach(c3);
		
		s.setSubjectState("ABC");
		s.Notify();
	}
}

//抽象通知者
//(增加、删除觀察者對象,通知觀察者)
abstract class Subject{
	//觀察者們
	private ArrayList<Observer> observers=new ArrayList<Observer>();
	
	//增加觀察者
	public void attach(Observer observer) {
		observers.add(observer);
	}
	
	//删除觀察者
	public void detach(Observer observer) {
		observers.remove(observer);
	}
	
	//通知每個同僚
	public void Notify() {
		for(int i=0;i<observers.size();i++) {
			observers.get(i).update();
		}
	}
}


//抽象觀察者類
//(更新狀态)
abstract class Observer{
	//更新狀态(虛函數)
	public abstract void update();
}


//具體被觀察者
class ConcreteSubject extends Subject{
	//具體被觀察者狀态
	private String subjectState;

	public String getSubjectState() {
		return subjectState;
	}

	public void setSubjectState(String subjectState) {
		this.subjectState = subjectState;
	}
}


//具體被觀察者
class ConcreteObserver extends Observer{
	//觀察者姓名
	private String name;
	//具體被觀察者的狀态
	private String observerState;
	//通知者
	private ConcreteSubject subject;
	
	//構造函數(設定觀察者、通知者姓名)
	public ConcreteObserver(String name, ConcreteSubject subject) {
		this.name = name;
		this.subject = subject;
	}
	
	//更新狀态
	public void update() {
		//擷取被觀察者的狀态
		observerState=subject.getSubjectState();
		System.out.println("觀察者"+name+"的新狀态是:"+observerState);
	}
}
           

觀察者模式的特點:

被觀察者不需要知道誰是它的觀察者,任何一個觀察者也不需要知道其他觀察者的存在。

什麼時候用觀察者模式:

當一個對象的改變需要同時改變其他的對象,而它不知道具體有多少個對象有待改變的時候。

隻有觀察者依賴于目标,而目标不依賴于觀察者。它們之間的主動權掌握在目标手中,隻有目标知道什麼時候需要通知觀察者,觀察者始終是被動的。

觀察者模式的不足:抽象通知者依賴于抽象觀察者。

4.java中的觀察者模式:

(以狼和羊為例)

package computer;

import java.util.Observable;
import java.util.Observer;

public class Test {
	public static void main(String[] args) {
		Wolf wolf=new Wolf("wolf1");
		Sheep sheep1=new Sheep("sheep1");
		Sheep sheep2=new Sheep("sheep2");
		Sheep sheep3=new Sheep("sheep3");
		//添加觀察者
		wolf.addObserver(sheep1);
		wolf.addObserver(sheep2);
		String wolfState="hungry";
		
		//狼叫
		wolf.shout(wolfState);
		//該方法中的notifyObservers(state)方法會自動調用各個觀察者的update()方法
	}
}

//狼(被觀察者)
class Wolf extends Observable{
	//狼名字
	private String name;

	public Wolf(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	//狼叫(參數為notifyObservers()方法要用的參數)
	public void shout(String state) {
		System.out.println("狼 "+name+" shouting!");
		//被觀察者狀态改變
		this.setChanged();
		//通知所有觀察者(參數為要改變的屬性)
		this.notifyObservers(state);
	}
}

//羊(觀察者)
class Sheep implements Observer{
	//羊的狀态
	private String state="eating";
	//羊的名字
	private String name;
	
	public Sheep(String name) {
		super();
		this.name = name;
	}

	public String getState() {
		return state;
	}

	public void setState(String state) {
		this.state = state;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void update(Observable o, Object arg) {
		Wolf wolf=(Wolf) o;
		System.out.println("狼 "+wolf.getName()+" shouting and "+arg+". "+name+"running.......");
		//重新設定觀察者的狀态
		setState("running");
	}
}