墨风如雪博客

  • 源码小店
  • 导航站
  • 登录
  • java
  • 资源分享
让AI使用变得如此简单
  1. 首页
  2. java
  3. 设计模式
  4. 正文

设计模式:观察者模式

2023年 5月 13日 160点热度 0人点赞 0条评论

观察者设计模式

观察者设计模式(Observer Design Pattern)是一种行为型设计模式,它定义了对象之间的一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会收到通知并自动更新。

观察者模式包含两个主要角色:Subject(主题)和 Observer(观察者)。Subject 是一个被观察的对象,它维护了一个观察者列表,当它的状态发生改变时,会通知所有观察者。Observer 是观察者对象,它注册到 Subject 中,以便在主题的状态改变时接收通知。

优点:

  1. 易于扩展:通过添加新的观察者对象,可以轻松地扩展和修改系统的行为。

  2. 松散耦合:主题和观察者之间的耦合度很低,它们可以独立地进行修改和扩展,从而提高代码的灵活性和可维护性。

  3. 分离关注点:观察者模式可以将关注点分离开来,使得主题对象只需要关注自己的状态,而不需要关注和处理观察者的行为。

缺点:

  1. 订阅通知的顺序不确定:当多个观察者对象订阅同一个主题对象时,它们接收通知的顺序是不确定的,可能会导致不同的行为结果。

  2. 观察者太多:当观察者对象的数量很多时,可能会导致通知操作的执行时间过长,从而影响系统性能。

以下是一个简单的 Java 代码示例,展示了如何实现观察者模式:

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

// 主题接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

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

// 具体主题类
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String message;

    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

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

    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }

    public void setMessage(String message) {
        this.message = message;
        notifyObservers();
    }
}

// 具体观察者类
class ConcreteObserver implements Observer {
    private String name;

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

    public void update(String message) {
        System.out.println(name + " received message: " + message);
    }
}

// 测试类
public class ObserverExample {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        subject.registerObserver(new ConcreteObserver("Alice"));
        subject.registerObserver(new ConcreteObserver("Bob"));
        subject.registerObserver(new ConcreteObserver("Charlie"));

        subject.setMessage("Hello, world!");
    }
}

在上面的例子中,我们定义了两个接口 Subject 和 Observer,分别用于定义主题和观察者的行为。然后,我们实现了一个具体的主题类 ConcreteSubject,该类维护了一个观察者列表,以及一个消息字符串,并提供了注册、删除和通知观察者的方法。在 setMessage 方法中,我们先设置消息字符串,然后调用 notifyObservers 方法来通知所有观察者。

最后,我们在 ObserverExample 类中使用观察者模式来测试代码。我们首先创建一个具体主题对象 subject,然后注册三个具体观察者对象,最后设置消息字符串。当设置消息字符串后,主题对象会自动通知所有观察者,并调用它们的 update 方法。

这个例子展示了如何使用观察者模式来实现对象之间的一对多依赖关系,并解决了代码扩展和耦合度的问题。在实际开发中,我们可以使用类似的方式来实现事件驱动的编程模型、GUI 应用程序中的组件交互等。

spring当中是如何使用的

在 Spring 中,迭代器模式被广泛应用于集合类的遍历和访问,例如在 Spring MVC 中,控制器返回的数据对象通常是一个集合对象,它可以被迭代器遍历并渲染到视图中。

以下是一个简单的 Java 代码示例,展示了如何在 Spring MVC 中使用迭代器模式来遍历集合对象:

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/users")
    public String userList(Model model) {
        List<User> users = userService.getAllUsers();
        model.addAttribute("users", users);
        return "userList";
    }
}

// userList.jsp
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
    <title>User List</title>
</head>
<body>
    <h1>User List</h1>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Email</th>
            </tr>
        </thead>
        <tbody>
            <c:forEach var="user" items="${users}">
                <tr>
                    <td>${user.id}</td>
                    <td>${user.name}</td>
                    <td>${user.email}</td>
                </tr>
            </c:forEach>
        </tbody>
    </table>
</body>
</html>

在上面的例子中,我们定义了一个控制器类 UserController,它使用 @Autowired 注解注入了一个 UserService 对象,并定义了一个 userList 方法,用于返回所有用户的列表。在 userList 方法中,我们获取了所有用户的列表,并使用 model.addAttribute 方法将它们添加到模型中,然后返回一个视图名 "userList"。

在视图 "userList" 中,我们使用 JSP 中的 c:forEach 标签来遍历用户列表,从而将它们渲染到 HTML 表格中。在 c:forEach 标签中,我们使用 EL 表达式 ${user.id}、${user.name} 和 ${user.email} 来获取用户的 ID、名称和电子邮件地址,并将它们渲染到表格中的对应单元格中。

这个例子展示了如何在 Spring MVC 中使用迭代器模式来遍历集合对象,并将它们渲染到视图中。在实际开发中,我们可以使用类似的方式来处理复杂的数据对象、渲染复杂的视图等。

而在平时的开发中,我们也可以使用迭代器模式来遍历和访问集合对象。以下是一个简单的 Java 代码示例,展示了如何使用迭代器模式来遍历列表对象:

List<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("cherry");

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String item = iterator.next();
    System.out.println(item);
}

在上面的例子中,我们创建了一个字符串列表 list,并使用 list.iterator() 方法获取了一个迭代器对象 iterator。然后,我们使用一个循环来遍历列表中的元素,并将它们打印出来。

这个例子展示了如何使用迭代器模式来遍历列表对象,并解决了代码重复和冗余的问题。在实际开发中,我们可以使用类似的方式来遍历数组、文件系统中的文件列表等。

过度使用可能造成的问题

虽然观察者设计模式可以有效地解耦主题对象和观察者对象,但是过度使用观察者设计模式也可能引发一些问题,如下所述:

  1. 性能问题:当观察者对象非常多时,主题对象在通知所有观察者对象时,可能会导致性能问题,因为每个观察者对象都需要执行相应的操作,从而增加了 CPU 开销和内存占用。

  2. 可维护性问题:使用观察者设计模式可能会降低代码的可维护性。由于观察者对象和主题对象之间的关系是动态的,并且可能在运行时改变,因此在代码中过度使用观察者对象可能会使代码变得复杂和难以理解,从而增加了代码的维护成本。

  3. 线程安全问题:在多线程环境下,使用观察者设计模式可能会引发线程安全问题。如果多个线程同时访问和修改同一个主题对象,那么它们可能会在同一个时间点上通知观察者对象,导致数据错误或不一致性。

因此,在使用观察者设计模式时,我们应该遵循一些最佳实践,如下所述:

  1. 控制观察者对象的数量:在实际开发中,我们应该尽量控制观察者对象的数量,避免过度使用观察者对象,从而减少通知操作的开销和内存占用。

  2. 使用异步通知:在某些场景下,我们可以考虑使用异步通知方式来通知观察者对象,从而减少主题对象的等待时间和观察者对象的响应时间,提高系统性能和可伸缩性。

  3. 处理线程安全问题:在多线程环境下,我们可以使用同步机制(如 synchronized 关键字)来保证主题对象的访问和修改的线程安全性,或者使用线程安全的集合对象(如 ConcurrentHashMap)来避免线程安全问题。另外,我们也可以使用不可变主题对象,并通过复制机制来实现线程安全。

观察者设计模式是一种非常有用的设计模式,可以有效地解耦主题对象和观察者对象。但是,在使用观察者设计模式时,我们应该注意性能、可维护性和线程安全等问题,从而保证代码的质量和可维护性。

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: java 教程 观察者模式 设计模式
最后更新:2023年 5月 11日

墨风如雪

一个热爱生活,热爱分享的程序员

打赏 点赞
< 上一篇
下一篇 >

文章评论

您需要 登录 之后才可以评论

墨风如雪

一个热爱生活,热爱分享的程序员

最新 热点 随机
最新 热点 随机
告别机械感!OpenAudio S1让AI声音活起来 Sora触手可及!微软必应AI视频生成器,全民创作时代来临? 阿里WebAgent开源:引领自主搜索新纪元 重磅炸弹!字节跳动开源BAGEL:70亿参数,统一多模态理解与生成,AI“全能王”诞生记! 小米MiMo-VL:7B参数,怎么就成了多模态界的“越级打怪王”? 炸裂!DeepSeek 8B 量化版降临:告别显存焦虑,你的 3080 Ti 也能玩转顶级大模型了!
炸裂!微软这门免费AI Agent新手课,GitHub近2万星,简直是宝藏!ComfyUI“打通任督二脉”:直接调用Veo2、GPT-4o等65大模型!一键串联你的AI工作流AI圈炸锅了!Mistral Medium 3:性能 SOTA,成本打骨折,企业玩家的新宠?字节终于开源“扣子”同款引擎了!FlowGram:AI 时代的可视化工作流利器告别“微信黑箱”!Chatlog:让你的聊天记录也能拥有“AI大脑”!字节跳动 Seed-Coder-8B:不靠人工洗数据,这80亿参数的小模型如何写出顶尖代码?
设计模式:建造者设计模式 风暴眼中的新王:阿里通义千问 Qwen2 登顶开源竞技场,Qwen2.5-Omni 或将掀起新浪潮? spring最顶级接口 beanfactory解析 递归函数详解 AI编程三剑客:Cline+DeepSeek R1+Claude3.5智能编码实战指南 每日算法题:字符串转换整数(atoi)
标签聚合
动态规划 设计模式 教程 spring deepseek AI java 算法

COPYRIGHT © 2023 墨风如雪博客. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

免责声明 - 隐私政策