23种设计模式——观察者模式

2年前 (2022) 程序员胖胖胖虎阿
253 0 0

目录

观察者模式(Observer)

理解

UML图

优缺点

观察者模式在各语言中的支持

Java

C#

实例

小丑表演

办公室摸鱼

投资者与股票


观察者模式(Observer)

本质:触发联动

目标对象变化时,会通知所有登记的观察者对象行动。

别名:

发布-订阅(Publish/Subscribe)模式
模型-视图(Model/View)模式
源-监听器(Source/Listener)模式
从属者(Dependents)模式。

理解

  • 是一对多的单向依赖:多个观察者对象同时观察一个目标对象, 观察者依赖于目标。
  • 相互观察时注意死循环
    • 若 A、B观察C,B、C观察A,则需要两套观察模式,否则死循环
  • 通知的顺序:同时
    • 多个观察者是平行的(虽然是循环,但几乎同时完成)

减少对象之间的耦合有利于系统的复用,但同时需要使这些低耦合度的对象行动协调一致(观察者对象行动的方法要保持参数一致)

UML图:

在这里插入图片描述

Subject:抽象被观察者(目标)

  • 一个目标可以被多个观察者观察。目标变化时,目标会通知所有登记的观察者
  • 拥有一个抽象观察者的引用

Observer:抽象观察者

  • 得到目标的通知时更新自己。更新方法,图上Updata()

ConcreteSubject:具体被观察者

  • 将状态存入具体现察者对象。自己变化时,给所有登记的观察者发出通知

ConcreteObserver:具体观察者

  • 拥有一个指向具体目标的引用

优缺点

优点:

  • 实现了观察者和被观察者之间的抽象耦合。
  • 动态联动
  • 广播通信。被观察者会向所有的登记的观察者发出通知。

缺点:

可能会引起无谓的操作。

由于采用广播方式,不管观察者需不需要,每个观察者都会被调用update方法

观察者模式在各语言中的支持

Java

1.Observer接口
Observer为java.util包下的一个接口,源码如下:

public interface Observer {
    void update(Observable o, Object arg);
}

该接口约定了观察者的行为

所有观察者需要在被观察对象发生变化时做出反应,所做的具体反应就是实现Observer接口的update方法。

  • 当前接口代表观察者,要与被观察对象交互,需要持有被观察对象Observable的引用,因此update方法一个参数的类型是Observable
  • 与调用者通信,则是使用Object类型的参数。该参数是调用者调用Observable实例的notifyObservers(Object obj)方法时传入的,也可以不传。

第一个参数是为观察者提供了一种拉取数据的方式,update中的业务可以根据所需去拉自己想要的被观察对象的信息(一般被观察对象中提供getter),第二个参数则是由调用者调用notifyObservers(Object obj)将一些信息推过来。通过这两个参数,观察者,被观察对象,调用者(调用通知刷新方法的可能是被观察对象本身,此时只存在观察者与被观察者两者)三者就联系起来了。

2.Observable类
java.util.Observable

该类实现了被观察者的功能

该类的成员变量和方法如下:

public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;
    public Observable(){};
    protected synchronized void setChanged(){};
    protected synchronized void clearChanged(){};
    public synchronized void addObserver(Observer o){};
    public synchronized void deleteObserver(Observer o) {};
    public synchronized void deleteObservers(){};
    public synchronized boolean hasChanged(){};
    public synchronized int countObservers(){};
    public void notifyObservers(){};
    public void notifyObservers(Object arg){};
}

C#

.NET中提供了Delegate与Event机制
 

实例

小丑表演

镇上来了一位小丑,为大家表演节目,所有观看的观众会根据小丑表演的精彩与否来做出相应的反应,比如表演的好就鼓掌喝彩,表演的不好就倒喝彩,表演完毕观众就退场。

分析:

  • 观众是观察者,应该实现Observer接口
  • 小丑是被观察者,应该继承Observable类

观众会根据小丑表演的状态改变自己的行为

package com.test;

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

//观众类
public class Viewer implements Observer{
	private int id;

	
	public Viewer(int id) {
		super();
		this.id = id;
	}


	public int getId() {
		return id;
	}


	public void setId(int id) {
		this.id = id;
	}


	@Override
	public void update(Observable o, Object arg) {
		Integer state=(Integer) arg;
		switch(state) {
			case Clown.good:
				applause();
				break;
			case Clown.bad:
				cheerback();
				break;
			case Clown.complete:
				exit();
				break;
		}
	}
	
	private void applause() {
		System.out.println(id+"号观众鼓掌了");
	}
	
	private void cheerback() {
		System.out.println(id+"号观众喝倒彩");
	}
	
	private void exit() {
		System.out.println(id+"号观众退场了");
	}

}
package com.test;

import java.util.Observable;
import java.util.Random;
//小丑类
public class Clown extends Observable{
	public static final int good=0;
	public static final int bad=1;
	public static final int complete=2;
	
	public void perform() {
		System.out.println("小丑开始表演");
		//0-2随机值
		int random=new Random().nextInt(2);
		switch(random) {
		case good:
			System.out.println("小丑表演得好");
			break;
		case bad:
			System.out.println("小丑表演得不好");
			break;
		}
		setChanged();
		//小丑的状态传给观众的update方法的第二个参数
		notifyObservers(random);
	}
	
	public void exit() {
		System.out.println("小丑表演结束");
		setChanged();
		//小丑的状态传给观众的update方法的第二个参数
		notifyObservers(complete);
	}

}
package com.test;

public class Test {

	public static void main(String[] args) {
		Clown c=new Clown();
		
		for(int i=1;i<4;i++) {
			Viewer v=new Viewer(i);
			c.addObserver(v);
			System.out.println(v.getId()+"号观众入席");
		}
		
		c.perform();
		c.exit();
	}

}

23种设计模式——观察者模式

办公室摸鱼

办公时间摸鱼, 在老板到来时,前台负责通知同事进入工作状态

  • 观察者:两个同事,需要实现Observer接口
  • 被观察者有两个:前台和老板,应该继承Observeable类
    • 前台通知:摸鱼的人改为工作状态
    • 老板通知:摸鱼的人被老板发现并且批评

    23种设计模式——观察者模式

package qiqi.work;

import java.util.Observable;

public class Boss extends Observable {
	private int state=0;//离开
	
	public void com() {
		System.out.println("我大老板回来了");
		state=2;//回来
		setChanged();//必须要写
		notifyObservers(state);//发出通知
		
	}

}
package qiqi.work;

import java.util.Observable;

public class Secretary extends Observable{
	private int state=0;//老板离开
	
	public void see() {
		System.out.println("老板回来了");
		state=1;//老板回来啦
		setChanged();
		notifyObservers(state);
	}

}
package qiqi.work;

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

public abstract class Observers implements Observer{
	protected String name;
	
	public Observers(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

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

	@Override
	public abstract void update(Observable o, Object arg);
	
	public abstract void see();
	public abstract void exit();
	public abstract void criticize();

}
package qiqi.work;

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

public class NBAObserver extends Observers{

	public NBAObserver(String name) {
		super(name);
		// TODO Auto-generated constructor stub
	}
	@Override
	public void update(Observable o, Object arg) {
		// TODO Auto-generated method stub
		Integer state=(Integer)arg;
		switch(state){
		case 0:
			see();break;
		case 1:
			exit();break;
		case 2:
			criticize();break;//老板通知
		}
		
	}
	@Override
	public void see() {
		// TODO Auto-generated method stub
		System.out.println(name+"看NBA");
	}

	@Override
	public void exit() {
		// TODO Auto-generated method stub
		System.out.println(name+"停止看NBA,开始工作");
	}

	@Override
	public void criticize() {
		// TODO Auto-generated method stub
		System.out.println(name+"你居然在工作时间看NBA,快工作!");
		
	}
	

}
package qiqi.work;

import java.util.Observable;

public class StockObserver extends Observers{

	public StockObserver(String name) {
		super(name);
		// TODO Auto-generated constructor stub
	}


	@Override
	public void see() {
		// TODO Auto-generated method stub
		System.out.println(name+"看股票");
	}

	@Override
	public void exit() {
		// TODO Auto-generated method stub
		System.out.println(name+"停止看股票,开始工作");
	}

	@Override
	public void criticize() {
		// TODO Auto-generated method stub
		System.out.println(name+"你居然在工作时间看股票,快工作!");
	}


	@Override
	public void update(Observable o, Object arg) {
		// TODO Auto-generated method stub
		Integer state=(Integer)arg;
		switch(state){
		case 0:
			see();break;
		case 1:
			exit();break;//秘书通知
		case 2:
			criticize();break;//老板通知
		}
		
	}

}
package qiqi.work;

public class Test {

	public static void main(String[] args) {
		
		NBAObserver nba=new NBAObserver("张三");
		StockObserver stock=new StockObserver("李四");
		Secretary s=new Secretary();
		s.addObserver(nba);
		s.addObserver(stock);
		s.see();
		
		Boss b=new Boss();
		b.addObserver(nba);
		b.addObserver(stock);
		b.com();

	}

}

23种设计模式——观察者模式

投资者与股票

注册的投资者在股票市场发生变化时,可以自动得到通知的功能

当观察者数量无法确定时,可以用一个List来保存观察者

23种设计模式——观察者模式

不使用Observer类和接口,代码如下:

package com.invest;

//观察者接口
public interface IInvestor {
	void update(Stock stock);
}
package com.invest;

//具体观察者
public class Investor implements IInvestor{
	private String name;
	private Stock stock;
	
	public Investor(String name) {
		super();
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Stock getStock() {
		return stock;
	}
	public void setStock(Stock stock) {
		this.stock = stock;
	}
	
	@Override
	public void update(Stock stock) {
		System.out.println(name+" "+stock.symbol+" "+stock.price);
	}

}
package com.invest;

import java.util.ArrayList;

//抽象被观察者
public abstract class Stock {
	protected String symbol;
	protected double price;
	private ArrayList<Investor> investors=new ArrayList<Investor>();

	public Stock(String symbol, double price) {
		super();
		this.symbol = symbol;
		this.price = price;
	}

	public String getSymbol() {
		return symbol;
	}

	public void setSymbol(String symbol) {
		this.symbol = symbol;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
		Notify();//状态改变,触发通知
	}
	
	public void Attach(Investor investor) {
		investors.add(investor);
	}
	
	public void Detach(Investor investor) {
		investors.remove(investor);
	}
	
	public void Notify() {
		for(Investor i:investors)
			i.update(this);
	}

}
package com.invest;

//具体被观察者
public class QQ extends Stock{

	public QQ(String symbol, double price) {
		super(symbol, price);
		// TODO Auto-generated constructor stub
	}
	
}
package com.invest;

public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Investor i1=new Investor("张三");
		Investor i2=new Investor("李四");
		
		Stock s=new QQ("腾讯",120.1);
		s.Attach(i1);
		s.Attach(i2);
		
		s.setPrice(120.4);
		s.setPrice(121.1);
		s.Detach(i2);
		s.setPrice(122.2);
	}

}

使用Observer接口和Observerable类,代码如下:

package com.invest1;

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

//观察者
public class Investor implements Observer{
	private String name;
	
	public Investor(String name) {
		super();
		this.name = name;
	}

	@Override
	public void update(Observable o, Object arg) {
		Integer a=(Integer)arg;
		if(a==Stock.getState()) 
			System.out.println(name+"买的股票:"+Stock.getSymble()+"价格变为"+Stock.getPrice());
	}
	

}

package com.invest1;

import java.util.Observable;

public class Stock extends Observable{
	private static String symble;
	private static double price;
	private static int state=0;//1表示状态变化,0表示不变
	
	public Stock(String symble, double price) {
		super();
		this.symble = symble;
		this.price = price;
	}
	
	public static String getSymble() {
		return symble;
	}
	public void setSymble(String symble) {
		this.symble = symble;
	}
	public static double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
		change();//价格改变,被观察者的状态改变
	}
	
	public void change() {
		setChanged();
		setState(1);
		notifyObservers(getState());//1表示状态变化,0表示不变
	}

	public static int getState() {
		return state;
	}

	public static void setState(int state) {
		Stock.state = state;
	}
	

}
package com.invest1;

public class Main {
	
	public static void main(String[] args) {
		Investor i1=new Investor("张三");
		Investor i2=new Investor("李四");
		
		Stock s=new Stock("谷歌",120.1);
		s.addObserver(i1);
		s.addObserver(i2);
		s.setPrice(122.1);
	}

}

23种设计模式——观察者模式

版权声明:程序员胖胖胖虎阿 发表于 2022年11月10日 下午10:08。
转载请注明:23种设计模式——观察者模式 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...