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

一、观察者模式概述​

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

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

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

三、代码结构图

相关推荐
火烧屁屁啦18 分钟前
【JavaEE进阶】初始Spring Web MVC
java·spring·java-ee
w_312345431 分钟前
自定义一个maven骨架 | 最佳实践
java·maven·intellij-idea
岁岁岁平安34 分钟前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA37 分钟前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
Q_192849990644 分钟前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
张国荣家的弟弟1 小时前
【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?
java·jar·bi
ZSYP-S1 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
yuanbenshidiaos1 小时前
C++----------函数的调用机制
java·c++·算法
是小崔啊2 小时前
开源轮子 - EasyExcel01(核心api)
java·开发语言·开源·excel·阿里巴巴
黄公子学安全2 小时前
Java的基础概念(一)
java·开发语言·python