【行为型模式】观察者模式

一、观察者模式概述​

软件系统其实有点类似观察者模式,目的:一个对象的状态或行为的变化将导致其他对象的状态或行为也发生改变,他们之间将产生联动

观察者模式属于对象行为型

  • 1.定义了对象之间一种一对多的依赖关系,让一个对象的改变能够影响其他对象。
  • 2.发生改变的对象称为观察目标,被通知的对象成为观察者。
  • 3.一个观察目标可以对应多个观察者。别名:发布-订阅(Public/subscribe)模式,模型-视图(Model/View)模式,源-监听器(Source/Listener)模式,从属者(Dependents)模式。

观察模式的优缺点

  • 优点
    • 1.可以实现表示层和数据逻辑层的分离。
    • 2.在观察目标和观察者之间建立了一个抽象的耦合。
    • 3.支持广播通信,简化了一对多系统设计的难度。
    • 4.符合开闭原则,添加新的具体观察者无须修改与原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便。
  • 缺点
    • 1.将所有的观察者都通知到会花费很多时间。
    • 2.如果存在循环依赖时可能会导致系统崩溃。
    • 3.没有相应得机制让观察者知道所观察得目标对象是怎么发生变化得,而只是知道观察目标发生了变化。
  • 适用环境
    • 1.一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将两个方面封装在独立得对象中方使它们可以各自独立地改变和复用。
    • 2.一个对象的改变将导致一个或多个其他对象发生改变,且并不知道具体有多少个对象将发生改变,也不知道这些对象是谁。
    • 3.需要在系统中创建一个触发链。

二、代码实现

主题(Subject)+观察者(Observer)=观察者模式

观察者模式的代码结构包含

  • 抽象主题(Subject):接口,抽象类;
  • 具体主题(ConcreteSubject):比如公众号;
  • 抽象观察者(Observer);
  • 具体观察者(ConcreteObserver);
2.1 战队控制实现代码
2.1.1 抽象主题用抽象类实现(抽象类类名AllyControlCenter)
java 复制代码
package Observe.ally;

import java.util.*;

//战队控制中心类:目标抽象类
public abstract class AllyControlCenter {
	protected String allyName;//战队名称
	//定义一个玩家集合
	protected ArrayList<Observer> players =new ArrayList<Observer>();
	public String getAllyname() {
		return allyName;
	}
	public void setAllyname(String allyName) {
		this.allyName = allyName;
	}
	//注册方法
	public void join(Observer obs) {
		System.out.println(obs.getName()+"加入"+this.allyName+"战队!");
		players.add(obs);
	}
	//注销方法
	public void quit(Observer obs) {
		System.out.println(obs.getName()+"退出"+this.allyName+"战队!");
		players.remove(obs);
	}
	//声明抽象通知方法
	public abstract void notifyObserver(String name);
}
2.1.2 具体主题实现(ConcreteAllyControlCenter)
java 复制代码
package Observe.ally;

public class ConcreteAllyControlCenter extends AllyControlCenter {
	public ConcreteAllyControlCenter(String allyName) {
		System.out.println(allyName+"战队组建成功!");
		System.out.println("-------------------------");
		this.allyName = allyName;
	}
	@Override
	public void notifyObserver(String name) {
		// TODO 自动生成的方法存根
		System.out.println(this.allyName+"战队紧急通知,盟友"+name+"遭受敌人袭击!");
		//遍历观察者集合,调用每一个盟友(自己除外)的支援方法
		for(Object obs : players) {
			if(!((Observer)obs).getName().equalsIgnoreCase(name)) {
				((Observer)obs).help();
			}
		}
	}

}
2.1.3 抽象观察类(接口实现,接口名为Observer)
java 复制代码
package Observe.ally;
//抽象观察类
public interface Observer {
	public String getName();
	public void setName(String name);
	public void help();//声明支援盟友方法
	//声明遭受攻击方法
	public void beAttacked(AllyControlCenter acc);
}
2.1.4 具体观察者(Player)
java 复制代码
package Observe.ally;

public class Player implements Observer{
	private String name;
	
	public Player(String name) {
		this.name =name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	//支援盟友方法的实现
	public void help() {
		System.out.println("坚持住:"+this.name+"来救你!");
	}
	//遭受攻击方法的实现,当遭受攻击时将调用战队控制中心的通知方法notifyObserver()来通知
	public void beAttacked(AllyControlCenter acc) {
		System.out.println(this.name+"被攻击!");
		acc.notifyObserver(name);
	}
}
2.1.5 main方法调用实现观察者模式
java 复制代码
package Observe.ally;

public class Client {
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		//定义观察者目标对象
		AllyControlCenter acc;
		acc= new ConcreteAllyControlCenter("金庸群侠");
		
		//定义四个观察者对象
		Observer player1,player2,player3,player4;
		player1 = new Player("杨过");
		acc.join(player1);
		player2 = new Player("令狐冲");
		acc.join(player2);
		player3 = new Player("张无忌");
		acc.join(player3);
		player4 = new Player("段誉");
		acc.join(player1);
		//某成员遭受攻击
		player1.beAttacked(acc);
	}

}
2.1.6 UML图
2.2 公众号代码实现
2.2.1 抽象主题用抽象接口实现(抽象接口名Subject)
java 复制代码
package Observe.Weixin_observation;
//公众号,主题对象
public interface Subject {
	//注册
	public void registerObserver(Observer o);
	//删除
	public void removeObserver(Observer o);
	//通知用户
	public void notifyObservers(String message);
}
2.2.2 具体主题实现(WeixinSubject
java 复制代码
package Observe.Weixin_observation;

import java.util.*;

public class WeixinSubject implements Subject {
	private List<Observer> users = new ArrayList<Observer>();
	String msg;
	@Override
	public void registerObserver(Observer o) {
		// TODO 自动生成的方法存根
		users.add(o);
	}

	@Override
	public void removeObserver(Observer o) {
		// TODO 自动生成的方法存根
		int i = users.indexOf(o);
		if(i>=0)
			users.remove(i);
	}

	@Override
	public void notifyObservers(String message) {
		// TODO 自动生成的方法存根
		//冒号表示范围==Observer必须在users里面
		for(Observer o:users) {
			o.update(message);
		}
	}
	//更新信息
	public void setMsg(String msg) {
		this.msg = msg;
		notifyObservers(msg);
	}
}
2.2.3 抽象观察类(接口实现,接口名为Observer)
java 复制代码
package Observe.Weixin_observation;

public interface Observer {
	//发送文本信息,推送
	public void update(String message);
}
2.2.4 具体观察者(WeixinUser)
java 复制代码
package Observe.Weixin_observation;

public class WeixinUser implements Observer {
	String name;
	public WeixinUser(String name) {
		super();
		this.name = name;
	}
	@Override
	public void update(String message) {
		// TODO 自动生成的方法存根
		System.out.println(name+",您好!"+message);
	}
	//关注/订阅公众号
	public void subscribeSubject(Subject o) {
		o.registerObserver(this);
	}
	//取消订阅
	public void deleteSubject(Subject o) {
		o.removeObserver(this);
	}
}
2.2.5 main方法调用实现观察者模式
java 复制代码
package Observe.Weixin_observation;

public class Test {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		//创建一个微信公众号
		WeixinSubject hdjdlgxydxfy = new WeixinSubject();
		WeixinUser user1 = new WeixinUser("user1");
		WeixinUser user2 = new WeixinUser("user2");
		WeixinUser user3 = new WeixinUser("user3");
		//用户关注
		user1.subscribeSubject(hdjdlgxydxfy);
		user2.subscribeSubject(hdjdlgxydxfy);
		user3.subscribeSubject(hdjdlgxydxfy);
		//推送消息
		hdjdlgxydxfy.setMsg("学院2020年体育课开始选课拉.....");
		//取消订阅
		user1.deleteSubject(hdjdlgxydxfy);
		hdjdlgxydxfy.setMsg("学院2020年体育课结束,下面是选课名单...");
	}

}
2.2.6 UML图

三、代码结构图

相关推荐
程序员-珍9 分钟前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
2401_8572979136 分钟前
招联金融2025校招内推
java·前端·算法·金融·求职招聘
福大大架构师每日一题1 小时前
23.1 k8s监控中标签relabel的应用和原理
java·容器·kubernetes
金灰1 小时前
HTML5--裸体回顾
java·开发语言·前端·javascript·html·html5
菜鸟一皓1 小时前
IDEA的lombok插件不生效了?!!
java·ide·intellij-idea
爱上语文1 小时前
Java LeetCode每日一题
java·开发语言·leetcode
bug菌1 小时前
Java GUI编程进阶:多线程与并发处理的实战指南
java·后端·java ee
程序猿小D2 小时前
第二百六十九节 JPA教程 - JPA查询OrderBy两个属性示例
java·开发语言·数据库·windows·jpa
极客先躯2 小时前
高级java每日一道面试题-2024年10月3日-分布式篇-分布式系统中的容错策略都有哪些?
java·分布式·版本控制·共识算法·超时重试·心跳检测·容错策略
夜月行者3 小时前
如何使用ssm实现基于SSM的宠物服务平台的设计与实现+vue
java·后端·ssm