Java笔试面试题AI答之设计模式(4)

news2024/11/16 13:41:04

文章目录

  • 16. 简述什么是观察者模式?
      • 基本概念
      • 主要特点
      • 实现方式
      • 应用场景
      • 优缺点
  • 17. 请列举观察者模式应用场景 ?
  • 18. 请用Java代码实现观察者模式的案例 ?
  • 19. 什么是装饰模式?
      • 定义与特点
      • 结构与角色
      • 工作原理
      • 优点
      • 应用场景
      • 示例
  • 20. 请用Java代码实现装饰者模式的案例 ?

16. 简述什么是观察者模式?

观察者模式(Observer Pattern),也被称为模型-视图(Model-View)模式、源-收听者(Listener)模式或从属者模式,是软件设计模式中的一种行为型模式。该模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并被自动更新。以下是观察者模式的详细解释:

基本概念

  • 观察者(Observer):等待被通知的对象,它持有对一个或多个主题(Subject)的引用,以便在主题状态发生变化时得到更新。
  • 主题(Subject):也被称为被观察者,当它的状态发生变化时,会主动通知所有注册的观察者对象,使得它们能够自动更新自己。

主要特点

  1. 松耦合:主题和观察者之间通过抽象接口进行交互,使得它们可以独立演化而不影响彼此。
  2. 一对多关系:一个主题可以有多个观察者,并且它们之间没有直接联系。
  3. 可扩展性:可以随时增加新的观察者或删除现有观察者,无需修改主题或观察者的代码。
  4. 实时性:实现了实时更新机制,当主题状态改变时能够即刻通知相关观察者。

实现方式

观察者模式通常包含以下几个角色:

  • 抽象主题(Subject):定义了一个用于保存观察者对象的集合以及一个用于增加、删除和通知观察者的接口。
  • 具体主题(Concrete Subject):实现了抽象主题定义的接口,用于管理具体的观察者对象集合,并在需要时向观察者发送通知。
  • 抽象观察者(Observer):定义了一个更新接口,该接口用于响应主题状态的变化。
  • 具体观察者(Concrete Observer):实现了抽象观察者接口,并在接收到主题的通知时执行相应的操作。

应用场景

观察者模式在许多应用中都有广泛的应用,特别是当存在对象之间的一对多关系,并且需要实时通知和更新时。以下是一些典型的应用场景:

  • 消息发布/订阅系统:观察者模式可以用于构建消息发布/订阅系统,其中消息发布者充当主题(被观察者),而订阅者则充当观察者。
  • 图形用户界面(GUI):在图形用户界面中,用户界面的各个部分(如按钮、文本框等)可以作为观察者,而它们所依赖的数据或状态则可以作为主题。当数据或状态发生变化时,界面元素会自动更新以反映这些变化。
  • 业务对象之间的交互:在业务系统中,不同业务对象之间可能存在复杂的依赖关系。通过使用观察者模式,可以将这些依赖关系解耦,使得当某个业务对象的状态发生变化时,能够自动通知并更新依赖它的其他业务对象。

优缺点

  • 优点
    • 降低了对象之间的耦合度,提高了系统的灵活性和可扩展性。
    • 实现了对象之间的动态关联,可以在运行时动态地添加或删除观察者。
    • 简化了对象之间的通信机制,使得系统更加易于理解和维护。
  • 缺点
    • 如果一个主题通知了太多的观察者,可能会导致系统性能下降。
    • 如果观察者和主题之间存在循环依赖关系,可能会导致系统崩溃。
    • 在某些情况下,观察者可能无法感知到其他已注册的新类型或特定类型的观察者。

总的来说,观察者模式是一种非常有用的设计模式,它能够帮助我们解决对象之间的一对多依赖关系问题,并提高系统的灵活性和可扩展性。然而,在使用时也需要注意其潜在的缺点和限制。

17. 请列举观察者模式应用场景 ?

观察者模式(Observer Pattern)是一种设计模式,主要用于当一个对象的状态发生变化时,能够自动通知多个依赖于它的对象并使它们同步更新。它是一种行为型模式,常用于实现发布-订阅机制。以下是观察者模式的一些主要应用场景:

  1. 图形用户界面(GUI)事件监听

    • 在图形用户界面编程中,按钮、文本框等控件的事件处理通常使用观察者模式。控件(如按钮)作为被观察者,当用户进行某些操作时(如点击按钮),会通知观察者(即事件处理器或监听器)来处理相应的事件。例如,当用户点击按钮时,按钮对象会通知所有注册的监听器,然后调用这些监听器的处理方法来响应点击事件。
  2. 数据模型与视图同步

    • 在模型-视图-控制器(MVC)架构中,观察者模式常用于数据模型和视图之间的更新同步。当模型中的数据发生变化时,所有依赖该模型的视图都会自动更新显示。例如,在图形化的应用程序中,如果数据模型发生改变,表格视图和图表视图等都会同步更新以反映最新数据。
  3. 发布-订阅系统

    • 观察者模式是发布-订阅系统的基础。在这种系统中,发布者(被观察者)发布消息,订阅者(观察者)订阅感兴趣的消息类型。当某个消息类型被发布时,订阅者会收到通知并执行相应的处理逻辑。这种模式常见于消息中间件系统,如Kafka或RabbitMQ,它们允许不同的服务订阅某个主题,当该主题发布消息时,所有订阅者都会接收消息并处理。
  4. 股票价格监控

    • 在金融系统中,股票价格可能频繁变动,多个不同的系统(如显示价格的终端、交易系统等)都依赖这些变化。观察者模式可以让股票价格的变化自动通知所有依赖该数据的系统。当股票价格更新时,所有注册的投资者或系统会收到通知,并相应调整其交易策略或显示界面。
  5. 缓存系统的失效通知

    • 在一些分布式系统中,当某个缓存中的数据失效时,观察者模式可以用于通知相关系统或服务进行缓存更新或重新加载数据。例如,当数据库中的数据被更新时,缓存层会收到通知,标记缓存数据失效,以确保下一次请求能获取到最新的数据。
  6. 社交媒体的通知机制

    • 在社交媒体平台中,当用户发布新动态时,所有关注者都应及时收到通知。这里的用户是被观察者,关注者是观察者。用户发布新内容时,平台会通知所有关注者。例如,在微博、推特等平台中,当某个用户发布新动态时,所有关注者都会在时间线上看到该动态。
  7. 日志系统

    • 在某些复杂的系统中,日志的记录可能需要发送到多个地方,如文件、数据库、监控系统等。观察者模式可以用于实现这样的需求,其中日志记录器充当被观察者,而观察者可以是日志分析器、报警系统等。当日志发生变化时,观察者将收到通知并执行相应的操作,如生成报告、发送警报等。
  8. 定时任务或调度器

    • 一些定时任务系统需要在指定的时间通知多个任务执行。观察者模式可以很好地支持这一功能。调度器作为被观察者,任务作为观察者,调度器到达指定时间后通知所有观察者执行任务。例如,定时任务调度器可以通知多个系统组件执行某些例行维护任务。
  9. 游戏中的状态变化通知

    • 在游戏开发中,某些对象的状态变化可能影响多个其他对象。例如,当游戏角色的生命值发生变化时,UI界面需要更新生命值显示,敌对角色可能需要调整攻击策略,音效系统可能需要播放不同的音效。观察者模式可以确保这些变化能够自动通知并同步更新到所有相关的对象。

综上所述,观察者模式在需要通知多个对象进行同步更新的场合具有广泛的应用价值,它能够提高系统的扩展性和可维护性。

18. 请用Java代码实现观察者模式的案例 ?

观察者模式(Observer Pattern)是一种行为设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

以下是一个使用Java实现的简单观察者模式案例:

首先,定义一个主题接口(Subject),它包含一个注册观察者、删除观察者以及通知观察者的方法:

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

public interface Subject {
    // 注册观察者
    void registerObserver(Observer o);

    // 删除观察者
    void removeObserver(Observer o);

    // 通知所有观察者
    void notifyObservers();
}

然后,定义一个观察者接口(Observer),它包含一个更新方法,用于在接收到通知时执行:

public interface Observer {
    // 接收通知时调用的更新方法
    void update(String message);
}

接下来,实现具体的主题类(ConcreteSubject),它实现了Subject接口,并维护了一个观察者列表:

public class ConcreteSubject implements Subject {
    private List<Observer> observers;
    private String subjectState;

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

    @Override
    public void registerObserver(Observer o) {
        if (!observers.contains(o)) {
            observers.add(o);
        }
    }

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

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

    // 用于设置主题状态并通知所有观察者
    public void setState(String state) {
        this.subjectState = state;
        notifyObservers();
    }

    // Getter和Setter(如果需要)
    public String getState() {
        return subjectState;
    }
}

最后,实现具体的观察者类(ConcreteObserver),它实现了Observer接口:

public class ConcreteObserver implements Observer {
    private String name;
    private String observerState;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        observerState = message;
        readObserverState();
    }

    private void readObserverState() {
        System.out.println(name + " received state: " + observerState);
    }
}

现在,我们可以使用这些类来演示观察者模式:

public class ObserverPatternDemo {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();

        Observer observer1 = new ConcreteObserver("Observer 1");
        Observer observer2 = new ConcreteObserver("Observer 2");

        subject.registerObserver(observer1);
        subject.registerObserver(observer2);

        subject.setState("Hello World!");

        // 如果需要,可以删除某个观察者
        // subject.removeObserver(observer1);
        // subject.setState("Another message");
    }
}

在这个例子中,ConcreteSubject 类维护了一个观察者列表,并在其状态改变时通过调用 notifyObservers() 方法来通知所有已注册的观察者。每个 ConcreteObserver 对象在接收到通知时都会更新自己的状态,并通过 readObserverState() 方法输出接收到的消息。

19. 什么是装饰模式?

装饰模式是一种常见的设计模式,主要用于在不改变原有类结构的情况下,动态地给对象增加新的功能或职责。这种模式通过创建一个包装对象(即装饰器)来包裹真实的对象,从而达到扩展对象功能的目的。以下是装饰模式的详细简述:

定义与特点

  • 定义:装饰模式(Decorator Pattern)动态地给一个对象增加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。
  • 特点
    • 多用组合,少用继承:通过对象间的组合关系来实现功能的扩展,而不是通过继承关系。
    • 开闭原则:对扩展开放,对修改关闭。可以在不修改原有类代码的情况下,通过增加新的装饰器类来扩展功能。
    • 透明性:装饰对象与真实对象有相同的接口,这样客户端就可以以相同的方式与它们交互,无需知道它们是真实对象还是装饰对象。

结构与角色

装饰模式包含以下几个角色:

  1. 抽象构件(Component)角色:定义一个对象的接口,可以给这些对象动态地添加一些职责。
  2. 具体构件(Concrete Component)角色:定义了一个具体的对象,也可以给这个对象添加一些职责。
  3. 装饰(Decorator)角色:持有一个构件(Component)对象的引用,并定义一个与抽象构件接口一致的接口。
  4. 具体装饰(Concrete Decorator)角色:负责给构件对象“贴上”一些新的职责。

工作原理

  • 装饰模式通过创建一个包装对象(即装饰器)来包裹真实对象。
  • 装饰器对象与真实对象有相同的接口,客户端可以通过这个接口与它们进行交互。
  • 装饰器对象可以在转发请求给真实对象之前或之后增加一些新的功能或行为。

优点

  • 灵活性:可以在不修改原有类代码的情况下,通过增加新的装饰器类来扩展功能。
  • 扩展性:遵循开闭原则,对扩展开放,对修改关闭。
  • 减少子类数量:通过组合关系替代继承关系,减少了子类的数量,降低了系统的复杂度。

应用场景

  • 当需要给某个对象动态地增加一些职责时。
  • 当不能使用继承的方式来扩展对象的功能时(例如,类已经被定义为final,或者出于设计上的考虑不希望产生大量的子类)。
  • 当一个类的功能比较复杂,而且需要经常扩展时,可以使用装饰模式来简化类的设计。

示例

假设有一个简单的图形界面程序,其中有一个按钮(Button)类。现在需要给这个按钮增加一些新的样式或功能,比如边框、颜色等。使用装饰模式,可以创建一个或多个装饰器类(如BorderDecorator、ColorDecorator等),每个装饰器类都负责给按钮增加一种特定的样式或功能。这样,就可以通过组合不同的装饰器来创建具有多种样式和功能的按钮对象,而无需修改原始的按钮类代码。

20. 请用Java代码实现装饰者模式的案例 ?

装饰者模式(Decorator Pattern)是一种用于动态地给一个对象添加一些额外的职责,就增加功能来说,装饰者模式相比生成子类更为灵活。这种模式创建了一个装饰者类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

下面是一个使用Java实现的装饰者模式案例,假设我们有一个咖啡类(Coffee),我们可以使用不同的调料(如奶精、摩卡等)来装饰它,增加它的口味。

首先,定义一个咖啡接口(Coffee)和一个具体的咖啡类(如Espresso)实现这个接口:

interface Coffee {
    double cost();
    String getDescription();
}

class Espresso implements Coffee {
    @Override
    public double cost() {
        return 1.99;
    }

    @Override
    public String getDescription() {
        return "Espresso";
    }
}

接下来,定义一个装饰者抽象类,它实现了Coffee接口,并持有一个Coffee对象的引用,用于调用实际咖啡的方法:

abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;

    public CoffeeDecorator(Coffee decoratedCoffee) {
        this.decoratedCoffee = decoratedCoffee;
    }

    @Override
    public double cost() {
        return decoratedCoffee.cost();
    }

    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription();
    }
}

现在,我们可以创建具体的装饰者类,比如MochaMilk,它们扩展了CoffeeDecorator类,并添加了额外的功能(如增加成本、修改描述):

class Mocha extends CoffeeDecorator {
    public Mocha(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }

    @Override
    public double cost() {
        return 0.20 + super.cost(); // 假设加摩卡需要额外0.20
    }

    @Override
    public String getDescription() {
        return super.getDescription() + ", Mocha";
    }
}

class Milk extends CoffeeDecorator {
    public Milk(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }

    @Override
    public double cost() {
        return 0.10 + super.cost(); // 假设加奶需要额外0.10
    }

    @Override
    public String getDescription() {
        return super.getDescription() + ", Milk";
    }
}

最后,我们可以使用这些类来创建一个具有多种口味的咖啡,并查看其成本和描述:

public class DecoratorPatternDemo {
    public static void main(String[] args) {
        Coffee espresso = new Espresso();
        System.out.println(espresso.getDescription() + " $" + espresso.cost());

        Coffee espressoMocha = new Mocha(espresso);
        System.out.println(espressoMocha.getDescription() + " $" + espressoMocha.cost());

        Coffee espressoMochaMilk = new Milk(espressoMocha);
        System.out.println(espressoMochaMilk.getDescription() + " $" + espressoMochaMilk.cost());
    }
}

输出将会是:

Espresso $1.99
Espresso, Mocha $2.19
Espresso, Mocha, Milk $2.29

这样,我们就通过装饰者模式在运行时动态地给咖啡添加了不同的调料,而无需修改咖啡类或创建新的咖啡子类。

答案来自文心一言,仅供参考
在这里插入图片描述

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

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

相关文章

队列的各种接口的实现(C)

队列的概念 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出FIFO(First In First Out) 入队列&#xff1a;进行插入操作的一端称为队尾 出队列&#xff1a;进行删除操作的一端称为队头 队列的实…

【GlobalMapper精品教程】088:按点线面空间位置选择案例

按点线面空间位置选择的原则为:点线面的排列组合。 文章目录 一、选择线要素附近的点二、选择相交或触碰所选线的区和线三、选择包含点的区要素四、选择选定区域内的点要素一、选择线要素附近的点 启动该工具之前,首先要选择线,例如,选择某一段铁路5km范围之内的县城驻地。…

nacos适配人大金仓的数据库

前言 在微服务架构中&#xff0c;服务发现和配置管理是关键组件。Nacos作为一个动态服务发现和配置管理平台&#xff0c;支持多种数据库作为其后端存储。本文将探讨如何在Nacos中适配人大金仓数据库&#xff0c;以及在此过程中的最佳实践。 Nacos简介 Nacos&#xff08;Nami…

安装 depot_tools 和 Windows 10 SDK 为在Windows下构建基于 chromium 的浏览器(103.0.5060.68 之二)

本文已首发于&#xff1a; 秋码记录 为何要安装depot_tools 虽然我们在上一篇 Windows构建基于 Chromium 的浏览器之环境准备篇安装 Visual Studio&#xff08;103.0.5060.68 之一&#xff09; &#xff0c;已经在Windows系统安装好了Visual Studio 2019 Community版本。 然…

第十二周:机器学习

目录 摘要 Abstract 一、非监督学习 二、word embedding 三、transformer 1、应用 2、encoder 3、decoder 四、各类attention 1、最常见的类别 2、其余种类 3、小结 总结 摘要 本周继续学习机器学习的相关课程&#xff0c;首先了解了监督学习和非监督学习的概…

数据结构与算法——Java实现 9.习题——删除链表倒数节点

目录 19. 删除链表的倒数第 N 个结点 方法1 通过链表长度直接删除 方法2 递归加入哨兵节点 ListNode 方法3 快慢指针法 苦难&#xff0c;区区挫折罢了&#xff0c;而我必定站在幸福的塔尖 —— 24.9.22 19. 删除链表的倒数第 N 个结点 给你一个链表&#xff0c;删除链表的倒数第…

【LeetCode】146. LRU缓存

1.题目 2.思想 3.代码 3.1 代码1 下面这是一版错误的代码。错误的原因在于逻辑不正确导致最后的代码也是不正确的。 class LRUCache:def __init__(self, capacity: int):self.time 0 # 用于全局记录访问的时间self.num2time {} # 数字到时间的映射self.key2val {} # 数字…

第十四章:html和css做一个心在跳动,为你而动的表白动画

💖 让心跳加速,传递爱意 💖 在这个特别的时刻,让爱在跳动中绽放!🌟 无论是初次相遇的心动,还是陪伴多年的默契,我们的心总在为彼此跳动。就像这颗炙热的爱心,随着每一次的跳动,传递着满满的温暖与期待。 在这个浪漫的季节,让我们一同感受爱的律动!无论你是在…

Linux文件IO(七)-复制文件描述符

在 Linux 系统中&#xff0c;open 返回得到的文件描述符 fd 可以进行复制&#xff0c;复制成功之后可以得到一个新的文件描述符&#xff0c;使用新的文件描述符和旧的文件描述符都可以对文件进行 IO 操作&#xff0c;复制得到的文件描述符和旧的文件描述符拥有相同的权限&#…

自学笔记之TVM编译器框架 ,核心特性,模型优化概述,AI应用落地

最近在学习一些和芯片 AI相关的知识&#xff0c;重点了解了一下TVM&#xff0c;我自己认为TVM在AI应用落地类似的项目中&#xff0c;用途还是非常广泛的&#xff0c;现在把一些重要的笔记贴在下面&#xff0c;有两篇原帖链接也附上&#xff0c;感兴趣的同学可以学习一下。 TVM…

宝塔linux 安装code-server指定对应的端口无法访问

这个一般就是nginx搞的鬼&#xff0c;如果服务正常启动&#xff0c;就是访问不了&#xff1b;大概就是宝塔安装的nginx配置没有代理code-server服务对应的端口&#xff0c;一般就是nginx配置文件的问题 安装默认的nginx会有一个配置文件 直接拉到最后会有一行这个&#xff0c…

(三十二)栈(stack)

文章目录 栈&#xff08;stack&#xff09;1.1 操作1.2 关于栈的题目1.2.1 出栈顺序1.2.2 入栈顺序1.3.3 括号匹配 这篇文章将会讲两个不同的数据类型&#xff0c;分别是栈与队列&#xff08;双向队列是两个的拓展&#xff09; 栈&#xff08;stack&#xff09; 栈是一种特殊的…

自闭症孩子送寄宿学校,给他们成长的机会

在自闭症儿童的教育与康复之路上&#xff0c;选择一种合适的寄宿方式对于孩子的成长至关重要。这不仅关乎到孩子能否获得专业的训练与关怀&#xff0c;还直接影响到他们未来的社交能力、独立生活能力以及心理健康。今天&#xff0c;我们将以广州的星贝育园自闭症儿童寄宿制学校…

stm32单片机个人学习笔记6(EXTI外部中断)

前言 本篇文章属于stm32单片机&#xff08;以下简称单片机&#xff09;的学习笔记&#xff0c;来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记&#xff0c;只能做参考&#xff0c;细节方面建议观看视频&#xff0c;肯定受益匪浅。 STM32入门教程-2023版 细…

【动态库的加载】【进程地址空间(三)】

目录 1. 宏观看待动态库的加载2. 进程地址空间第二讲2.1 程序没有加载前的地址2.2 程序加载后的地址 3. 动态库的地址 再谈进程地址空间时&#xff0c;【Linux】动静态库 我们先讲一个关于动态库是如何加载的话题&#xff0c;再引入进程地址空间&#xff0c;再次谈论该话题。 …

在ComfyUI中,Cross-Attention优化方案应该选哪个?

&#x1f431;‍&#x1f409;背景 在comfyui中&#xff0c;如果你使用了秋叶的启动器&#xff0c;会在高级选项中看到这样一行选项&#xff1a;Cross-Attention优化方案&#xff0c;右边有个下拉框&#xff0c;可以选择的选项有4个&#xff0c;如下图&#xff1a; 那么&#…

设计模式之观察者模式例题

答案&#xff1a;D 知识点&#xff1a; 观察者模式意图是定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新 状态模式 意图&#xff1a;允许一个对象在其内部状态改变时改变它的行为

【verilog】4. gtkwave的调用

文章目录 前言实验步骤 前言 进行 数电 FPGA 实验 实验步骤 将 GTKwave 的 bin 文件夹路径添加到 “系统环境变量” 的 “Path” 中 启动 debugger wizard, 设置观测信号 编译选择 2进制 文件 点击 start programming connect debugger 选择触发方式 Run 自动打开 gtkwave&a…

[Meachines] [Medium] Querier XLSM宏+MSSQL NTLM哈希窃取(xp_dirtree)+GPP凭据泄露

信息收集 IP AddressOpening Ports10.10.10.125TCP:135, 139, 445, 1433, 5985, 47001, 49664, 49665, 49666, 49667, 49668, 49669, 49670, 49671 $ nmap -p- 10.10.10.125 --min-rate 1000 -sC -sV -Pn PORT STATE SERVICE VERSION 135/tcp open msrp…

【若依RuoYi-Vue | 项目实战】帝可得后台管理系统(二)

文章目录 一、人员管理1、需求说明2、生成基础代码&#xff08;1&#xff09;创建目录菜单&#xff08;2&#xff09;添加数据字典&#xff08;3&#xff09;配置代码生成信息&#xff08;4&#xff09;下载代码并导入项目 3、人员列表改造&#xff08;1&#xff09;基础页面&a…