设计模式之观察者模式 (六)

本文介绍了观察者模式,通过YY直播订阅场景作为示例,解释了观察者模式的工作原理。在模式中,一个目标对象管理并通知其观察者列表状态变化。Java中的Observer接口和Observable类作为实现示例,展示了如何创建观察者和被观察者。通过一个直播平台类和主播类的代码,演示了如何订阅和通知订阅者,强调了模式将观察者和被观察者责任分离的特点。
摘要由CSDN通过智能技术生成

说到观察者模式,在学习这个模式的过程中,我联想了许多观察者模式的应用场景,这个模式应该算项目中最有可能会用到的一个模式吧,比如在早年的YY直播横行的年代,我一开电脑就是先打开YY,因为我的YY里订阅了很多喜欢的主播,在主播开播的时候,YY自动会推送我一个开播提醒,我想,这就应该是观察者模式了吧。(订阅-发布模式)

 定义:观察者模式(有时又被称为发布-订阅模式、模型-视图模式、源-收听者模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实作事件处理系统。

以上定义与类图来自百度百科

由类图与定义我们可以知道,观察者模式就是有一个类管理所有观察者(持有一个观察者列表),并在被观察者发生变化时调用方法notify()通知那些观察者列表里的所有观察者,同时观察者需要实现一个观察者接口,才可以订阅以及被接收通知。

在JDK中,有现成的观察者接口与一个被观察的类。下面截取部分代码。

//观察者接口
public interface Observer {
    //这个方法是观察者在观察对象产生变化时所做的响应动作,参数分别为观察的对象和一个预留参数
    void update(Observable o, Object arg);

}
import java.util.Vector;

//被观察者类
public class Observable {
    //用来标记和判断被观察者是否发生了变化
    private boolean changed = false;
    //一个观察者的列表
    private Vector obs;
    
    public Observable() {
    obs = new Vector();
    }
    
    //notifyObservers(Object arg)的重载方法
    public void notifyObservers() {
    notifyObservers(null);
    }
    //通知观察者我已经变化了,你需要调用你的update方法了
    public void notifyObservers(Object arg) {
        //用来存放观察者当时的状态,有点类似与备忘录模式,记录当前观察者的状态,在后面通知时如果有变化也不受影响
        Object[] arrLocal;
    //这个同步块同步了获取观察者列表的过程,期间无法对观察者列表做改动了
    synchronized (this) {
        //判断被观察者是否发生变化了
        if (!changed)
                return;
            //将此时的所有的观察者放入上面的数组
            arrLocal = obs.toArray();
            //重置状态
            clearChanged();
        }
        //此时已经得到了所有需要通知的观察者的"备忘录数组",此时如果有观察者取消订阅之类的操作,都不影响通知之前所有观察者调用update
        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

    //删除所有观察者,类似取消订阅
    public synchronized void deleteObservers() {
    obs.removeAllElements();
    }

    //标记被观察者发生变化了
    protected synchronized void setChanged() {
    changed = true;
    }
    //重置发生变化的标记
    protected synchronized void clearChanged() {
    changed = false;
    }
    //判断观察者是否变化了
    public synchronized boolean hasChanged() {
    return changed;
    }
}

上面的Observer就是类图中的Observer抽象观察者接口,Observable就是类图中的Subject,拥有一个观察者的列表,有一个notify的方法用于通知所有列表中的观察者。

接下来举个例子,就是开头所说的直播订阅。下面是具体的观察者类。

package test;

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

//观察者类,就是观众类,需要实现Observer接口
public class Viewer1 implements Observer {

	String name;

	public Viewer1(String name) {
		this.name = name;
	}

	// 重写update做的方法
	@Override
	public void update(Observable o, Object arg) {
		if(o instanceof Player) {
			Player player = (Player) o;
			System.out.println(player.getName() + "开播啦,房间标题为" + player.getTitle() + name + "快去看看吧!");
		}
	}

	// 订阅一个主播
	public void subscribe(String name) {
		Platform.getInstance().subscribe(name, this);
	}

}

这里我写了一个中间的平台类,类似某鱼TV,用来存放所有的主播,以及提供一个订阅的功能。

package test;

import java.util.HashMap;
import java.util.Map;
import java.util.Observer;

public class Platform {
        //存放所有主播
	public Map<String, Player> players = new HashMap<String, Player>();
        //单例模式
	private Platform() {
	}

	public static Platform getInstance() {
		return Instance.platformInstance;
	}

	private static class Instance {
		static Platform platformInstance = new Platform();
	}
        //在平台上添加主播
	public void addPlayer(Player player) {
		players.put(player.getName(), player);
	}
        //一个订阅主播的方法
	public void subscribe(String name, Observer observer) {
		players.get(name).addObserver(observer);
	}

}

下面就是具体的主播类了。

package test;

import java.util.Observable;
//主播类,需要继承被观察者类
public class Player extends Observable {

	String name;
	String title;
        //在构造函数里向平台添加主播
	public Player(String name) {
		this.name = name;
		Platform.getInstance().addPlayer(this);
	}
        //主播上线之后会调用的方法,在这里通知所有订阅了该主播的观众
	public void online(String title) {
		System.out.println(name + "上线开播! 房间名:" + title);
		this.title = title;
		setChanged();
		notifyObservers();
	}

	public String getName() {
		return name;
	}

	public String getTitle() {
		return title;
	}

}

下面测试一下功能吧

package test;

public class testA {
	public static void main(String[] args) {
		// 有两个主播分别为uzi和董小飒~
		Player uzi = new Player("uzi");
		Player dongxiaosa = new Player("dongxiaosa");

		// 有三个用户
		Viewer1 viewer1 = new Viewer1("张三");
		Viewer1 viewer2 = new Viewer1("李四");
		Viewer1 viewer3 = new Viewer1("王五");

		// 他们分别订阅了主播,其中第三个观众谁都没订阅
		viewer1.subscribe("uzi");
		viewer1.subscribe("dongxiaosa");
		viewer2.subscribe("uzi");

		// 主播开播啦
		uzi.online("你的迟到很危险!");
		dongxiaosa.online("今天玩玩LOL");
	}
}

控制台打印

个人觉得这个模式还是蛮好玩的,总结一下吧,这里的主播类并不需要关心我具体要通知谁,只需要知道要通知的人实现了一个观察者接口,所以订阅的观众需要实现一个观察者的接口。这个模式分离了观察者和被观察者的责任,就像观众只需要订阅即可,不用关心其他事情,主播只需要notify即可通知,不需要知道具体要通知谁谁谁了,因为具体的通知列表,在观众那边就已经操作好了(订阅和取消订阅)。

注:由于我的水平有限,有些地方说的可能有问题?欢迎大家指出,互相讨论互相学习进步!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值