行为型设计模式(五):访问者模式 观察者模式

访问者模式 Visitor

1、什么是访问者模式

访问者模式允许定义一些不改变数据结构的前提下的操作。通过这种方式,可以在不修改元素类的情况下定义新的操作。访问者模式常用于对复杂对象结构进行操作,而又不希望在这些对象上破坏封装性。

2、为什么使用访问者模式

  1. 访问者模式将数据结构和操作分离,使得新增操作更加灵活,而不影响数据结构。
  2. 可以通过定义新的访问者来增加新的操作,而无需修改元素类,可扩展性强

3、如何使用访问者模式

设计实现一个图形编辑器,包含不同图形类型和对应的不同的操作

// 抽象元素类
interface Shape {
    void accept(Visitor visitor);
}

// 具体元素类1:圆形
class Circle implements Shape {
    private int radius;

    Circle(int radius) {
        this.radius = radius;
    }

    public int getRadius() {
        return radius;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

// 具体元素类2:矩形
class Rectangle implements Shape {
    private int width;
    private int height;

    Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

// 抽象访问者
interface Visitor {
    void visit(Circle circle);

    void visit(Rectangle rectangle);
}

// 具体访问者1:移动操作
class MoveVisitor implements Visitor {
    private int deltaX;
    private int deltaY;

    MoveVisitor(int deltaX, int deltaY) {
        this.deltaX = deltaX;
        this.deltaY = deltaY;
    }

    @Override
    public void visit(Circle circle) {
        System.out.println("Moving circle with radius " + circle.getRadius() + " by (" + deltaX + ", " + deltaY + ")");
    }

    @Override
    public void visit(Rectangle rectangle) {
        System.out.println("Moving rectangle with width " + rectangle.getWidth() + " and height " + rectangle.getHeight() + " by (" + deltaX + ", " + deltaY + ")");
    }
}

// 具体访问者2:缩放操作
class ScaleVisitor implements Visitor {
    private double scaleFactor;

    ScaleVisitor(double scaleFactor) {
        this.scaleFactor = scaleFactor;
    }

    @Override
    public void visit(Circle circle) {
        System.out.println("Scaling circle with radius " + circle.getRadius() + " by factor " + scaleFactor);
    }

    @Override
    public void visit(Rectangle rectangle) {
        System.out.println("Scaling rectangle with width " + rectangle.getWidth() + " and height " + rectangle.getHeight() + " by factor " + scaleFactor);
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Shape circle = new Circle(5);
        Shape rectangle = new Rectangle(10, 8);

        Visitor moveVisitor = new MoveVisitor(2, 3);
        Visitor scaleVisitor = new ScaleVisitor(1.5);

        // 执行移动操作
        circle.accept(moveVisitor);
        rectangle.accept(moveVisitor);

        // 执行缩放操作
        circle.accept(scaleVisitor);
        rectangle.accept(scaleVisitor);
    }
}

4、是否存在缺陷和不足

如果系统中新增了一个元素类,所有的具体访问者类都需要修改,不符合开闭原则。

5、如何缓解缺陷和不足

可以通过引入抽象访问者,将新增元素类的访问方法定义在抽象访问者中,然后具体访问者类只需要实现必要的访问方法。

观察者模式 Observer

1、什么是观察者模式

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象。当主题对象状态发生变化时,所有依赖它的观察者都会得到通知并自动更新。

2、为什么使用观察者模式

  1. 观察者模式实现了发布者和订阅者之间的松耦合,使得它们可以独立变化,不影响彼此。
  2. 新的观察者可以随时加入,而不影响发布者的实现,可扩展性强。

3、如何使用观察者模式

设计实现一个简单的新闻订阅系统,其中有多个订阅者订阅不同类型的新闻

import java.util.ArrayList;
import java.util.List;

// 主题接口
interface Subject {
    void addObserver(Observer observer);

    void removeObserver(Observer observer);

    void notifyObservers(String news);
}

// 具体主题:新闻发行
class NewsPublisher implements Subject {
    private List<Observer> observers;

    NewsPublisher() {
        this.observers = new ArrayList<>();
    }

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers(String news) {
        for (Observer observer : observers) {
            observer.update(news);
        }
    }
}

// 观察者接口
interface Observer {
    void update(String news);
}

// 具体观察者1:普通订阅者
class RegularSubscriber implements Observer {
    private String name;

    RegularSubscriber(String name) {
        this.name = name;
    }

    @Override
    public void update(String news) {
        System.out.println(name + " received regular news: " + news);
    }
}

// 具体观察者2:紧急订阅者
class UrgentSubscriber implements Observer {
    private String name;

    UrgentSubscriber(String name) {
        this.name = name;
    }

    @Override
    public void update(String news) {
        System.out.println(name + " received urgent news: " + news);
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 创建新闻发行主题
        NewsPublisher newsPublisher = new NewsPublisher();

        // 创建订阅者
        Observer regularSubscriber1 = new RegularSubscriber("Alice");
        Observer regularSubscriber2 = new RegularSubscriber("Bob");
        Observer urgentSubscriber = new UrgentSubscriber("Charlie");

        // 订阅者订阅主题
        newsPublisher.addObserver(regularSubscriber1);
        newsPublisher.addObserver(regularSubscriber2);
        newsPublisher.addObserver(urgentSubscriber);

        // 发布新闻
        newsPublisher.notifyObservers("Important news: COVID-19 vaccine breakthrough!");
        newsPublisher.notifyObservers("Regular news: Weather forecast for the week");

        // 移除一个订阅者
        newsPublisher.removeObserver(regularSubscriber2);

        // 再次发布新闻
        newsPublisher.notifyObservers("Urgent news: Emergency evacuation due to natural disaster!");
    }
}

4、是否存在缺陷和不足

  1. 在观察者模式中,观察者的更新顺序是不确定的,可能导致一些依赖顺序的问题。
  2. 通知模式比较单一,通知观察者的方式是同步的,如果某个观察者的更新操作耗时较长,可能影响整体性能。

5、如何缓解缺陷和不足

  1. 可以使用队列将观察者的更新操作异步执行,避免影响主题的通知效率。
  2. 可以引入顺序控制机制,明确观察者的更新顺序。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv8改进 | 主干篇 | 利用SENetV1改进网络结构 (ILSVRC冠军得主)

一、本文介绍 本文给大家带来的改进机制是SENet&#xff08;Squeeze-and-Excitation Networks&#xff09;其是一种通过调整卷积网络中的通道关系来提升性能的网络结构。SENet并不是一个独立的网络模型&#xff0c;而是一个可以和现有的任何一个模型相结合的模块(可以看作是一…

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《计及风电不确定性的多场景多时段安全约束机组组合解耦求解方法》

这个标题涉及到一种解决在能源系统中考虑风电不确定性的方法。让我们逐步分解这个标题&#xff0c;以便更好地理解其含义&#xff1a; 计及风电不确定性&#xff1a; 这指的是在能源系统中&#xff0c;风力发电的产出具有不确定性。因为风速是难以预测的&#xff0c;风力发电的…

nodejs+vue+ElementUi大学新生入学系统的设计与实现1hme0

采用B/S模式架构系统&#xff0c;开发简单&#xff0c;只需要连接网络即可登录本系统&#xff0c;不需要安装任何客户端。开发工具采用VSCode&#xff0c;前端采用VueElementUI&#xff0c;后端采用Node.js&#xff0c;数据库采用MySQL。 涉及的技术栈 1&#xff09; 前台页面…

TokenFlow详解

https://github.com/omerbt/TokenFlow/issues/25 https://github.com/omerbt/TokenFlow/issues/31 https://github.com/omerbt/TokenFlow/issues/32 https://github.com/eps696/SDfu register_extended_attention_pnp1. 为所有BasicTransformerBlock layer的attn1重构forward2.…

LeetCode 剑指 Offer II 054. 所有大于等于节点的值之和

给定一个二叉搜索树&#xff0c;请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。 提醒一下&#xff0c;二叉搜索树满足下列约束条件&#xff1a; 节点的左子树仅包含键 小于 节点键的节点。 节点的右子树仅包含键 大于 节点键的节点。 左右子树也必须…

【计数DP】牛客小白月赛19

登录—专业IT笔试面试备考平台_牛客网 题意 思路 首先做法一定是计数 dp 然后状态设计&#xff0c;先设 dp[i] 然后看影响决策的因素&#xff1a;两边的火焰情况&#xff0c;那就 dp[i][0/1][0/1]表示 前 i 个&#xff0c;该位有无火焰&#xff0c;该位右边有无火焰的方案数…

Kioptrix-3

靶场下载地址 https://download.vulnhub.com/kioptrix/KVM3.rar 信息收集 # Nmap 7.94 scan initiated Thu Dec 21 21:52:25 2023 as: nmap -sn -oN live.nmap 192.168.1.0/24 Nmap scan report for 192.168.1.1 (192.168.1.1) Host is up (0.00048s latency). MAC Address:…

2024年PMP考试新考纲-PMBOK第七版-项目管理原则真题解析(续2)

很多在备考2024年PMP考试的小伙伴问华研荟&#xff0c;从8月份以后把PMBOK第七版纳入PMP考试范围后&#xff0c;难不难&#xff1f;PMBOK第七版怎么考&#xff1f;尤其是第七版中的十二大项目管理原则读起来很晦涩难懂&#xff0c;这部分怎么考&#xff1f;该如何备考呢&#x…

Linux---基础操作命令

内容导航 类别内容导航机器学习机器学习算法应用场景与评价指标机器学习算法—分类机器学习算法—回归机器学习算法—聚类机器学习算法—异常检测机器学习算法—时间序列数据可视化数据可视化—折线图数据可视化—箱线图数据可视化—柱状图数据可视化—饼图、环形图、雷达图统…

JavaWeb—html, css, javascript, dom,xml, tomcatservlet

文章目录 快捷键HTML**常用特殊字符替代:****标题****超链接标签****无序列表、有序列表****无序列表**:ul/li 基本语法**有序列表ol/li:****图像标签(img)**** 表格(table)标签****表格标签-跨行跨列表格****form(表单)标签介绍****表单form提交注意事项**div 标签p 标签sp…

Android可折叠设备完全指南:展开未来

Android可折叠设备完全指南&#xff1a;展开未来 探索如何使用Android Jetpack组件折叠和展开设备。 近年来&#xff0c;科技界见证了可折叠设备的革命性趋势。这些设备融合了便携性和功能性的创新特点&#xff0c;使用户能够在不同的形态之间无缝切换。在本博客中&#xff0c…

照片墙案例

整体效果&#xff1a; HTML部分&#xff1a; <body><div class"content"><header><h1>A silent world</h1><span>Image Wall with jQuery and CSS3</span></header><div class"iw_wrapper"><ul…

3D数字化系统建设

以3D可视化、数字化技术为基础&#xff0c;其实&#xff0c;很多传统的系统软件都可以重新做一下。 比如&#xff1a;以下这个使用场景&#xff1a;零售门店陈列&#xff1b; 还有&#xff0c;数字化仓储系统&#xff0c;3D数字化供应链系统&#xff0c;3D数字化的生产系统&a…

.NET中的Swagger使用

目录 前言 一、Swagger是什么&#xff1f; 二、如何Swagger文档说明的信息 1.在AddSwaggerGen方法中写入文档信息 2.运行效果 二、文档UI界面标题、路由设置 1.在中间件UseSwaggerUI方法中配置 三、文档UI界面添加接口注释 1.在 .csproj中配置 2.在AddSwaggerGen方法中配置Incl…

MFC 菜单

目录 MFC菜单 菜单使用 添加菜单资源 将菜单设置到窗口 ON_COMMAND消息处理 命令消息 WM_COMMAND 的处理顺序 设置菜单项状态 右键菜单 MFC菜单 在Win32编程中&#xff0c;使用菜单句柄 HMENU 来标识菜单&#xff0c;在MFC中使用CMenu类对象表示菜单。封装了关于菜单的…

MATLAB - 四元数(quaternion)

系列文章目录 前言 一、简介 四元数是一种四元超复数&#xff0c;用于三维旋转和定向。 四元数的表示形式为 abicjdk&#xff0c;其中 a、b、c 和 d 为实数&#xff0c;i、j 和 k 为基元&#xff0c;满足等式&#xff1a;i2 j2 k2 ijk -1。 四元数集用 H 表示&#xff0c…

vmware安装中标麒麟高级服务器操作系统软件 V7.0操作系统

vmware安装中标麒麟高级服务器操作系统软件 V7.0操作系统 1、下载中标麒麟高级服务器操作系统软件 V7.0镜像2、安装中标麒麟高级服务器操作系统软件 V7.0操作系统 1、下载中标麒麟高级服务器操作系统软件 V7.0镜像 官方提供使用通道 访问官网 链接: https://www.kylinos.cn/ 下…

【Python】基于flaskMVT架构与session实现博客前台登录登出功能

目录 一、MVT说明 1.Model层 2.View层 3.Template层 二、功能说明 三、代码框架展示 四、具体代码实现 models.py 登录界面前端代码 博客界面前端代码&#xff08;profile.html&#xff09; main.py 一、MVT说明 MVT架构是Model-View-Template的缩写&#xff0c;是…

VS(Visual Studio)更改文件编码

vs默认编码是GB2312,更改为UTF-8 工具->自定义

Tomcat与Netty比较

Tomcat介绍Tomcat支持的协议Tomcat的优缺点Netty介绍Netty支持的协议Netty的优点和缺点Tomcat和Netty的区别Tomcat和Netty的应用场Tomcat和Netty来处理大规模并发连接的优化Tomcat与Netty的网络模型的区别Tomcat与Netty架构设计拓展 Tomcat介绍 Tomcat是一个免费的、开放源代码…