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

一、观察者模式概述​

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

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

  • 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图

三、代码结构图

相关推荐
Sunsets_Red9 分钟前
待修改莫队与普通莫队优化
java·c++·python·学习·算法·数学建模·c#
葡萄城技术团队12 分钟前
在 Java 中优化 MySQL 查询以提升性能
java·开发语言·mysql
杀死那个蝈坦16 分钟前
短链接生成-基于布隆过滤器和唯一索引
java·数据库·微服务·oracle·rocketmq
慕白Lee16 分钟前
Java foreach在lambda的foreach遍历中退出操作(lambda foreach break)
java
winfield82119 分钟前
Java 中大量闲置 MySQL 连接的解决方案(从根因到落地)
java·mysql
moxiaoran575322 分钟前
Java开发中VO的使用
java·开发语言
计算机毕设指导622 分钟前
基于微信小程序图像识别的智能垃圾分类系统【源码文末联系】
java·spring boot·mysql·微信小程序·小程序·分类·maven
LJianK128 分钟前
前后端接口常见传参
java·spring
独自破碎E30 分钟前
消息队列如何保证消息的有效性?
java·开发语言·rocketmq·java-rocketmq
38242782731 分钟前
使用 webdriver-manager配置geckodriver
java·开发语言·数据库·爬虫·python