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

观察者模式
1)概述
1.定义

定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

2.作用

建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。

在观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。

3.结构图

在这里插入图片描述

4.角色

Subject(目标):目标又称为主题,指被观察的对象,在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify(),目标类可以是接口,也可以是抽象类或具体类。

ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义的抽象业务逻辑方法,如果无须扩展目标类,则具体目标类可以省略。

Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update(),因此又称为抽象观察者。

ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer中定义的update()方法,通常在实现时,可以调用具体目标类的attach()方法将自己添加到目标类的集合中或通过detach()方法将自己从目标类的集合中删除。

5.代码实现

观察者模式描述了如何建立对象与对象之间的依赖关系,以及如何构造满足这种需求的系统。

抽象目标类Subject

import java.util.*;abstract class Subject {//定义一个观察者集合用于存储所有观察者对象protected ArrayList observers<Observer> = new ArrayList();//注册方法,用于向观察者集合中增加一个观察者public void attach(Observer observer) {observers.add(observer);}//注销方法,用于在观察者集合中删除一个观察者public void detach(Observer observer) {observers.remove(observer);}//声明抽象通知方法public abstract void notify();
}

具体目标类ConcreteSubject

public class ConcreteSubject extends Subject {//实现通知方法public void notify() {//遍历观察者集合,调用每一个观察者的响应方法for(Object obs:observers) {((Observer)obs).update();}}	
}

抽象观察者Observer

interface Observer {//声明响应方法public void update();
}

具体观察者ConcreteObserver

public class ConcreteObserver implements Observer {//实现响应方法public void update() {//具体响应代码}
}
6.注意

在复杂的情况下,具体观察者类ConcreteObserver的update()方法在执行时需要使用到具体目标类ConcreteSubject中的状态(属性),因此在ConcreteObserver与ConcreteSubject之间有时候还存在关联或依赖关系,在ConcreteObserver中定义一个ConcreteSubject实例,通过该实例获取存储在ConcreteSubject中的状态。

2)完整解决方案
1.结构图

在这里插入图片描述

AllyControlCenter充当抽象目标类,ConcreteAllyControlCenter充当具体目标类,Observer充当抽象观察者,Player充当具体观察者。

2.代码实现
import java.util.*;//抽象观察类
interface Observer {public String getName();public void setName(String name);public void help(); //声明支援盟友方法public void beAttacked(AllyControlCenter acc); //声明遭受攻击方法
}//战队成员类:具体观察者类
class Player implements Observer {private String name;public Player(String name) {this.name = name;}public void setName(String name) {this.name = name;}public String getName() {return this.name;}//支援盟友方法的实现public void help() {System.out.println("坚持住," + this.name + "来救你!");}//遭受攻击方法的实现,当遭受攻击时将调用战队控制中心类的通知方法notifyObserver()来通知盟友public void beAttacked(AllyControlCenter acc) {System.out.println(this.name + "被攻击!");acc.notifyObserver(name);		}
}//战队控制中心类:目标类
abstract class AllyControlCenter {protected String allyName; //战队名称protected ArrayList<Observer> players = new ArrayList<Observer>(); //定义一个集合用于存储战队成员public void setAllyName(String allyName) {this.allyName = allyName;}public String getAllyName() {return this.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);
}//具体战队控制中心类:具体目标类
class ConcreteAllyControlCenter extends AllyControlCenter {public ConcreteAllyControlCenter(String allyName) {System.out.println(allyName + "战队组建成功!");System.out.println("----------------------------");this.allyName = allyName;}//实现通知方法public void notifyObserver(String name) {System.out.println(this.allyName + "战队紧急通知,盟友" + name + "遭受敌人攻击!");//遍历观察者集合,调用每一个盟友(自己除外)的支援方法for(Object obs : players) {if (!((Observer)obs).getName().equalsIgnoreCase(name)) {((Observer)obs).help();}}		}
}

客户端类

class Client {public static void main(String[] args) {//定义观察目标对象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(player4);//某成员遭受攻击player1.beAttacked(acc);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/818764.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PCB整理

1.加工工艺流程&#xff1a; 开料磨边 、烘板、内光成像、内层腐刻、内层AOI、内层黑化、层压、钻孔、沉铜加厚、外光成像、外层腐刻、外层AOI、印阻焊、阻焊成像、丝印字符、涂覆保护层、二次钻孔、外形加工、电测试、烘板包装。 2.层叠结构&#xff1a; 3.基材&#xff1a;覆…

开源模型应用落地-chatglm3-6b-gradio-入门篇(七)

一、前言 早前的文章&#xff0c;我们都是通过输入命令的方式来使用Chatglm3-6b模型。现在&#xff0c;我们可以通过使用gradio&#xff0c;通过一个界面与模型进行交互。这样做可以减少重复加载模型和修改代码的麻烦&#xff0c; 让我们更方便地体验模型的效果。 二、术语 2.…

2024蓝桥A组E题

成绩统计 问题描述格式输入格式输出样例输入样例输出评测用例规模与约定解析参考程序难度等级 问题描述 题目有问题方差定义那加平方&#xff08;vi-v&#xff09; 格式输入 输入的第一行包含三个正整数n,k,T &#xff0c;相邻整数之间使用一个空格分隔。 第二行包含n个正整数…

Kubernetes(k8s)集群搭建部署,master节点配置

目录 1.切换为root用户 2.关闭防火墙&#xff0c;关闭swap分区和禁用SElinux 3.安装docker 4.更改daemon.json文件&#xff0c;指定 Docker 守护进程使用的 cgroup 驱动程序 5.重启docker服务 6.配置kubernetes.repo 7.安装Kubelet、Kubeadm、Kubectl 8.设置开机自启 …

【数据结构|C语言版】单链表应用

前言1. 基于单链表实现通讯录1.1 知识要求1.2 功能要求 2. 代码总结2.1 SeqList.h2.2 SeqList.c2.3 Contact.h2.4 Contact.c2.5 test.c 后言 上期回顾&#xff1a;【数据结构|C语言版】单链表 前言 各位小伙伴大家好&#xff01;上期小编讲解了单链表相关知识&#xff0c;在此…

【Go】原子并发操作

目录 一、基本概念 支持的数据类型 主要函数 使用场景 二、基础代码实例 开协程给原子变量做加法 统计多个变量 原子标志判断 三、并发日志记录器 四、并发计数器与性能监控 五、优雅的停止并发任务 worker函数 Main函数 应用价值 Go语言中&#xff0c;原子并发操…

【Linux】Linux基础与常用指令大全

文章目录 操作系统是什么&#xff1f;1. Linux家族介绍2. Linux的安装方式3. 常用指令3.1 ls [选项] [目录/文件]&#xff08;显示目录或文件信息&#xff09;3.2 pwd&#xff08;显示当前所在目录&#xff09;3.3 任意指令加上 --help&#xff08;查看指令的用法&#xff09;3…

ThinkPHP V5.1框架源码

源码下载地址&#xff1a;ThinkPHP V5.1.zip www WEB部署目录&#xff08;或者子目录&#xff09; ├─application 应用目录 │ ├─common 公共模块目录&#xff08;可以更改&#xff09; │ ├─module_name 模块目录 │ │ ├─common.php 模块函数文件 │ │ ├─controll…

一文掌握 React 开发中的 JavaScript 基础知识

前端开发中JavaScript是基石。在 React 开发中掌握掌握基础的 JavaScript 方法将有助于编写出更加高效、可维护的 React 应用程序。 在 React 开发中使用 ES6 语法可以带来更简洁、可读性更强、功能更丰富,以及更好性能和社区支持等诸多好处。这有助于提高开发效率,并构建出更…

线性表概念及顺序表的实现

文章目录 前言一、线性表1.定义2.特点3.一般线性表的抽象数据类型定义 二、线性表的顺序存储&#xff08;顺序表&#xff09;1.基本概念2.数组实现顺序表3.顺序表中基本操作的具体实现4.顺序表总结 总结 前言 T_T此专栏用于记录数据结构及算法的&#xff08;痛苦&#xff09;学…

MyBatis 源码分析系列文章导读

1.本文速览 本篇文章是我为接下来的 MyBatis 源码分析系列文章写的一个导读文章。本篇文章从 MyBatis 是什么&#xff08;what&#xff09;&#xff0c;为什么要使用&#xff08;why&#xff09;&#xff0c;以及如何使用&#xff08;how&#xff09;等三个角度进行了说明和演…

记一次对某高校微信小程序的漏洞挖掘

挖掘目标的部署在微信的资产(减少信息的收集&#xff0c;毕竟一般web站点没有账号密码不好进入后台&#xff0c;挖掘功能点少) 寻找目标的微信小程序(非原图) 招生小程序打不开&#xff0c;只能挖掘管理系统 进入后发现存在上报安全隐患功能&#xff0c;可以上传图片 准备上传…

【面经】操作系统/Linux

1、计算机的五大单元 电脑的五大单元包括&#xff1a;输入单元、输出单元、控制单元、算数逻辑单元、存储单元五大部分。其中CPU占有控制、算术逻辑单元&#xff0c;存储单元又包含内存与辅助内存&#xff1b; 2、什么是操作系统 操作系统&#xff1a;负责管理协调我们计算机…

Qt QStyle详解

1.简介 QStyle类是 Qt 框架中用于控制应用程序界面元素外观的一个抽象基类。这个类提供了一种方式来定制窗口部件&#xff08;widgets&#xff09;的绘制和行为&#xff0c;可以通过改变主题或风格来更改应用程序的外观&#xff0c;而无需修改窗口部件本身的代码。 Qt包含一组…

python爬虫------- Selenium下篇(二十三天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

CAN帧中的ACK位

1&#xff1a;先看官方文档对ACK的解释 All nodes that have received the matching CRC sequence (and, in FD Frames the matching stuff count) shall send an ACK within the ACK slot by overwriting the recessive bit of the transmitter by a dominant bit (they send…

求圆、圆球和圆柱的面积和体积(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h> //定义π常量的值&#xff1b; # define π 3.141526int main() {//初始化变量值&#xff1b;float r, h, S1, S2, P1, V1, V2;int judge 0;//提示用户&#x…

Python基于flask的豆瓣电影分析可视化系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

mid_360建图和定位

录制数据 roslaunch livox_ros_driver2 msg_MID360.launch使用fast-lio 建图 https://github.com/hku-mars/FAST_LIO.git 建图效果 使用python做显示 https://gitee.com/linjiey11/mid360/blob/master/show_pcd.py 使用 point_lio建图 https://github.com/hku-mars/Point…

【数据结构】【C++】AVL树的模拟实现(插入、判断、旋转)

文章目录 1 概念2 实现2.1 AVL树结点的定义2.2 AVL树的插入2.2.1 AVL树的插入规则2.2.2 旋转2.2.2.1 左单旋2.2.2.2 右单旋2.2.2.3 左右双旋2.2.2.4 右左双旋 2.2.3 总结 3 平衡判断4 删除5 源码 1 概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二…