【设计模式-4.1】行为型——观察者模式

news2025/1/20 13:33:30

说明:本文介绍设计模式中行为型设计模式中的,观察者模式;

商家与顾客

观察者模式属于行为型设计模式,关注对象的行为。以商家与顾客为例,商家有商品,顾客来购买商品,如果商家商品卖完了,顾客则购买失败。如下:

(Shop,商家类,提供购买、进货方法)

/**
 * 商家
 */
public class Shop {

    /**
     * 商品
     */
    private String product;

    public Shop() {
        this.product = "无商品";
    }

    /**
     * 出货
     * @return
     */
    public String getProduct() {
        return product;
    }

    /**
     * 进货
     * @param product
     */
    public void setProduct(String product) {
        this.product = product;
    }
}

(Buyer,顾客类,注入商店对象,购买商店商品)

/**
 * 顾客
 */
public class Buyer {

    private String name;

    private Shop shop;

    public Buyer(String name, Shop shop) {
        this.name = name;
        this.shop = shop;
    }

    /**
     * 买家购买商品
     */
    public void buy() {
        System.out.println(name + "来购买:" + shop.getProduct());
    }
}

(Client,客户端,演示购买动作)

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        Shop shop = new Shop();
        new Buyer("张三", shop).buy();

        shop.setProduct("橘子");
        new Buyer("李四", shop).buy();
    }
}

(执行结果)

在这里插入图片描述

分析上面的行为,可以发现一点缺陷。当商家的商品发生变化时,无法主动的,自发的通知顾客,只有顾客来购买时,才知道商品的信息。因此,我们考虑是否可以在商家类内部维护一个“顾客列表”,当商品信息发生变化时,调用顾客列表中所有顾客对应的方法,达到主动通知客户的目的。如下:

(Shop,商家类,维护一个顾客列表,新增一个通知顾客的方法)

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

/**
 * 商家
 */
public class Shop {

    /**
     * 商品
     */
    private String product;

    /**
     * 顾客列表
     */
    private List<Buyer> buyers;

    public Shop() {
        this.product = "无商品";
        this.buyers = new ArrayList<>();
    }

    /**
     * 添加顾客
     * @param buyer
     */
    public void addBuyer(Buyer buyer) {
        this.buyers.add(buyer);
    }
    
    /**
     * 移除顾客
     * @param buyer
     */
    public void removeBuyer(Buyer buyer) {
        this.buyers.remove(buyer);
    }

    /**
     * 出货
     * @return
     */
    public String getProduct() {
        return product;
    }

    /**
     * 进货
     * @param product
     */
    public void setProduct(String product) {
        this.product = product;
        notifyBuyers();
    }

    /**
     * 通知顾客
     */
    public void notifyBuyers() {
        for (Buyer buyer : buyers) {
            buyer.buy(product);
        }
    }
}

(Buyer,顾客抽象类,创建一个购买商品的抽象方法)

/**
 * 顾客
 */
public abstract class Buyer {

    /**
     * 顾客姓名
     */
    protected String name;

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

    /**
     * 买家购买商品
     */
    public abstract void buy(String product);
}

(FruitBuyer,水果买家,只购买水果类的商品)

/**
 * 水果买家
 */
public class FruitBuyer extends Buyer{

    public FruitBuyer(String name) {
        super(name);
    }

    @Override
    public void buy(String product) {
        if (product.contains("水果")) {
            System.out.println(name + ":来购买了水果");
        }
    }
}

(PhoneBuyer,手机买家,只购买手机类的商品)

/**
 * 手机买家
 */
public class PhoneBuyer extends Buyer{

    public PhoneBuyer(String name) {
        super(name);
    }

    @Override
    public void buy(String product) {
        if (product.contains("手机")) {
            System.out.println(name + ":来购买了手机");
        }
    }
}

(Client,客户端,模拟购买行为,张三只购买手机,买了一次后就不再需要了)

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        Shop shop = new Shop();
        PhoneBuyer phoneBuyer = new PhoneBuyer("张三");
        FruitBuyer fruitBuyer = new FruitBuyer("李四");

        shop.addBuyer(phoneBuyer);
        shop.addBuyer(fruitBuyer);

        shop.setProduct("苹果手机");
        shop.setProduct("各种水果");
        shop.removeBuyer(phoneBuyer);

        System.out.println("=================水果和手机降价了=================");
        shop.setProduct("水果和手机降价了");

    }
}

执行结果。当商家的商品信息有变化时,会通知到对应的顾客来购买。

在这里插入图片描述

类比现实生活,小村庄里只有一家商店。我们需要购买某样日用品,去商店购买,店长说没有,下个月才进货。很自然的,我们会和店长说,那我留下电话,进货了打电话通知我。

其中,留下电话,可以类比为将顾客注册到商店类中,而打电话则是调用顾客类对应的方法。

Spring中的体现

观察者模式,是一种订阅-发布的模式。在上面的例子中,商家是发布者,顾客是订阅者,当商家商品信息有变动时,发布信息,顾客接收。

Spring框架中,就有观察者模式的应用。如下:

(Customer,消费者类)

import org.springframework.context.ApplicationEvent;

public class Customer extends ApplicationEvent {

    private String message;

    public Customer(Object source, String message) {
        super(source);
        this.message = message;
    }


    public String getMessage() {
        return message;
    }
}

(CustomListener1,消费者1号)

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class CustomListener1 implements ApplicationListener<Customer> {

    @Override
    public void onApplicationEvent(Customer customer) {
        System.out.println("1号订阅者收到消息: " + customer.getMessage());
    }
}

(CustomListener2,消费者2号)

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class CustomListener2 implements ApplicationListener<Customer> {

    @Override
    public void onApplicationEvent(Customer customer) {
        System.out.println("2号订阅者收到消息: " + customer.getMessage());
    }
}

(Publisher,发布者)

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

@Component
public class Publisher {

    @Autowired
    private ApplicationEventPublisher eventPublisher;

    public void publishCustomEvent(String message) {
        eventPublisher.publishEvent(new Customer(this, message));
    }
}

(在测试类中,发布信息)

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest
@RunWith(SpringRunner.class)
public class PublisherTest {

    @Autowired
    private Publisher publisher;

    @Test
    public void test1() {
        publisher.publishCustomEvent("Hello World!");
    }
}

执行结果,2个订阅者都收到了消息;

在这里插入图片描述

以上就是观察者模式的实现;

总结

本文参考《设计模式的艺术》、《秒懂设计模式》两书

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

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

相关文章

【Leetcode题单】(01 数组篇)刷题关键点总结02【统计数组中的元素】

【Leetcode题单】&#xff08;01 数组篇&#xff09;刷题关键点总结02【统计数组中的元素】&#xff08;6题&#xff09; 统计数组中的元素645. 错误的集合 Easy697. 数组的度 Easy448. 找到所有数组中消失的数字 Easy442. 数组中重复的数据 Medium41. 缺失的第一个正数 Hard27…

【问题解决】Linux内核编译安装后磁盘空间已满问题

Linux内核编译安装后磁盘空间已满问题解决过程 【注】本文为个人遇到Linux内核经过make&#xff0c;make modules……乃至最后install以后VMware磁盘空间爆炸的情况后&#xff0c;而又不想重装虚拟机&#xff0c;自己找资料实现解决的&#xff0c;文章中很多链接是来自别的博主…

python动态圣诞下雪图

运行图片 代码 import pygame import random# 初始化Pygame pygame.init()# 创建窗口 width, height 800, 600 screen pygame.display.set_mode((width, height)) pygame.display.set_caption(Christmas Tree)# 定义颜色 GREEN (34, 139, 34) RED (255, 0, 0) WHITE (255…

GAMES101:作业2记录

总览 在上次作业中&#xff0c;虽然我们在屏幕上画出一个线框三角形&#xff0c;但这看起来并不是那么的有趣。所以这一次我们继续推进一步——在屏幕上画出一个实心三角形&#xff0c;换言之&#xff0c;栅格化一个三角形。上一次作业中&#xff0c;在视口变化之后&#xff0…

Redis--13--缓存一致性问题

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 缓存一致性问题1、先更新缓存&#xff0c;再更新DB方案二&#xff1a;先更新DB&#xff0c;再更新缓存方案三&#xff1a;先删缓存&#xff0c;再写数据库推荐1&…

Python ctypes:揭秘高级Python与底层交互秘籍

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com ctypes是Python标准库中的外部函数库&#xff0c;允许Python调用动态链接库中的函数。它提供了与C兼容的数据类型和允许Python调用共享库中的函数&#xff0c;对系统级编程和与硬件交互非常有用。 基本用法 加…

基于Django框架搭建的协同过滤算法电影推荐网站-爬取的豆瓣电影数据

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介概述技术栈实现流程 二、功能三、系统四. 总结 一项目简介 # 电影推荐网站介绍 概述 该电影推荐网站是基于Django框架搭建的&#xff0c;旨在为用户提供个…

jdk1.8 hashmap源码阅读

目录 hashmap 成员变量 hashmap支持null键吗&#xff1f;为什么&#xff1f; 当扩容的时候&#xff0c;所有元素都会重新计算hash值吗&#xff1f; 怎么减少扩容次数 为什么node数组的大小是2的n次&#xff1f; 1.8和1.7的区别 1.8为啥要用红黑树&#xff1f; 扩容机制…

12.3_黑马MybatisPlus笔记(上)

目录 02 03 04 05 06 07 ​编辑 thinking:system.out::println?​编辑 thinking&#xff1a;list.of? 08 thinking&#xff1a;RequestParam和 ApiParam注解使用&#xff1f; thinking&#xff1a;RequestParam 和PathVariable的区别&#xff1f; ​编辑 ​编…

“B2B+OMS方案”,赋能家电巨头构建BC订单一体化能力,促进业务增长|徐礼昭

某国际知名家电电器品牌&#xff0c;年营收超过5000亿元。该电器企业其整体业务分三大类&#xff1a;线上线下B2B2C业务、线下B2B业务以及DTC零售业务。 随着业务的发展&#xff0c;该电器品牌对2B业务及DTC业务的数字化系统能力支撑需要更加全面和立体&#xff0c;以适应业务…

Sharding-Jdbc(4):Sharding-Jdbc分库

1 新建数据库 创建ds_0数据库和ds_1数据库&#xff0c;在两个数据库新建表如下&#xff1a; CREATE TABLE t_order (order_id bigint(20) NOT NULL,user_id bigint(20) NOT NULL,PRIMARY KEY (order_id) ) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_bin; 2 新建maven项目…

基于姿态估计的3D动画生成

在本文中&#xff0c;我们将尝试通过跟踪 2D 视频中的动作来渲染人物的 3D 动画。 在 3D 图形中制作人物动画需要大量的运动跟踪器来跟踪人物的动作&#xff0c;并且还需要时间手动制作每个肢体的动画。 我们的目标是提供一种节省时间的方法来完成同样的任务。 我们对这个问题…

SmartSoftHelp8,FrameCode极速二次开发框架源码

1.winform outlook style UI C/S 极速开发框架 netframework 2.0 2.winform toolbar style UI C/S 极速开发框架 netframework 2.0 3.WPF toolbar style UI C/S 极速开发框架 netframework 4.0 4.Xadmin-UI jquery B/S 极速开发框架 5.Vue element UI B/S…

ArrayList 与 顺序表 (附洗牌算法)!

曾经我也是一枚学霸&#xff0c;直到有一天想去学渣的世界看看&#xff0c;结果就找不到回去的路了。 目录 1. 线性表 2.顺序表 2.1 接口的实现 3. ArrayList简介 4. ArrayList使用 4.1 ArrayList的构造 4.2 ArrayList常见操作 4.3 ArrayList的遍历 4.4 ArrayList的扩…

永倍达电商模式分析:创新商业模式引领新时代购物潮

在2019年底&#xff0c;全球新冠疫情席卷&#xff0c;导致大量实体经济倒闭&#xff0c;人们纷纷居家躲避&#xff0c;经济陷入下行&#xff0c;企业家面临倒闭威胁。永倍达成立于2020年&#xff0c;是陕西永倍达电子商务有限公司的品牌&#xff0c;而其母公司实际上是天津铸源…

Stable Diffusion 系列教程 - 1 基础准备(针对新手)

使用SD有两种方式&#xff1a; 本地&#xff1a; 显卡要求&#xff1a;硬件环境推荐NVIDIA的具有8G显存的独立显卡&#xff0c;这个显存勉勉强强能摸到门槛。再往下的4G可能面临各种炸显存、炼丹失败、无法生成图片等各种问题。对于8G显存&#xff0c;1.0模型就不行&#xff0…

前端入门(四)Ajax、Promise异步、Axios通信、vue-router路由、组件库

文章目录 AjaxAjax特点 Promise 异步编程&#xff08;缺&#xff09;Promise基本使用状态 - PromiseState结果 - PromiseResult AxiosVue中使用AxiosAxios请求方式getpostput和patchdelete并发请求 Vue路由 - vue-router单页面Web应用&#xff08;single page web application&…

C++ string类(2)—成员访问、插入、删除、替换、查找和交换操作

目录 一、成员访问 1、[ ]&at 2、front( )&back( ) 二、插入元素 三、删除元素 四、替换元素 五、查找元素 1、查找第一次出现位置 2 、在指定范围内查找 六、交换字符串 七、c_str 八、rfind&substr 一、成员访问 1、[ ]&at 虽然二者功能一样&…

LeetCode | 101. 对称二叉树

LeetCode | 101. 对称二叉树 OJ链接 在本函数里不好进行判断&#xff0c;我们另外定义一个函数来如果两个都相等为空&#xff0c;就返回true一个为空&#xff0c;一个不为空都不为空,就比较值然后递归1的左&#xff0c;2的右&#xff0c;1的右&#xff0c;2的左 bool _isSymm…

javaee实验:MVC 框架技术应用——URL 映射及方法参数的使用

目录 urlmvc框架mvc框架的设计mvc流程 实验目的实验内容实验过程创建项目创建项目结构编写代码简单测试一下 url 和 Hypertext 以及 HTTP 一样&#xff0c;URL 是 Web 中的一个核心概念。它是浏览器用来检索 web 上公布的任何资源的机制 URL 代表着是统一资源定位符&#xff…