实际开发中的协变与逆变案例:数据处理流水线

news2024/11/23 20:51:54

在实际开发中,协变(? extends T逆变(? super T 常常出现在处理数据流的场景中。我们通过一个简单的例子——设计一个通用的数据处理流水线,来深入理解它们的使用。


需求描述

假设我们在做一个电商项目,需要处理不同类型的订单数据:

  1. 数据源会提供各种类型的订单(如普通订单、会员订单、促销订单等)。
  2. 我们需要把这些订单传递到处理器进行处理。
  3. 不同的处理器可能对父类或子类的数据有不同的操作需求。

基本类型定义

我们有一个基本的订单类和几个子类:

// 父类:订单
class Order {
    private String id;
    public Order(String id) { this.id = id; }
    public String getId() { return id; }
}

// 子类:普通订单
class RegularOrder extends Order {
    public RegularOrder(String id) { super(id); }
}

// 子类:会员订单
class MemberOrder extends Order {
    public MemberOrder(String id) { super(id); }
}

设计目标:通用数据处理流水线

我们要设计两个通用的方法:

  1. 读取订单数据的工具(协变场景)。
  2. 将订单数据传递给处理器(逆变场景)。

1. 协变案例:只读订单数据

**场景:**我们需要一个工具方法,可以接受任意类型的订单列表(普通订单、会员订单等),并读取这些订单信息,但不对列表内容做修改。

代码实现:

// 工具方法:读取订单列表
public static void readOrders(List<? extends Order> orders) {
    for (Order order : orders) {
        System.out.println("订单ID:" + order.getId());
    }
}

协变的意义:

  • ? extends Order 表示“接受 Order 及其子类列表”。
  • 我们只读取列表里的数据,不向列表中添加任何内容。

调用示例:

List<RegularOrder> regularOrders = List.of(new RegularOrder("R001"), new RegularOrder("R002"));
List<MemberOrder> memberOrders = List.of(new MemberOrder("M001"), new MemberOrder("M002"));

// 读取普通订单
readOrders(regularOrders);

// 读取会员订单
readOrders(memberOrders);

协变的关键点:

  • 允许传入子类型列表(如 List<RegularOrder>)。
  • 只能“读”,不能“写”。
    • 如果试图往列表中添加元素,编译器会阻止。
orders.add(new RegularOrder("R003")); // 编译报错:不能添加数据!

2. 逆变案例:处理订单数据

**场景:**我们有一个订单处理器,需要把普通订单传递进去进行处理操作。由于不同的处理器可能接收更通用的 Order 类型,我们希望代码更灵活。

代码实现:

// 工具方法:添加订单到处理器
public static void processOrders(List<? super RegularOrder> orders) {
    orders.add(new RegularOrder("R003")); // 安全添加普通订单
    System.out.println("订单已处理!");
}

逆变的意义:

  • ? super RegularOrder 表示“接受 RegularOrder 及其父类的列表”。
  • 我们可以向列表中添加 RegularOrder 或其子类的实例。

调用示例:

List<Order> allOrders = new ArrayList<>(); // 容器可以是父类类型
processOrders(allOrders);

逆变的关键点:

  • 允许操作父类列表(如 List<Order>)。
  • 只能“写”,不能安全地“读”。

为什么不能读?
读取的数据类型不确定,只能当作 Object 处理:

Object obj = orders.get(0); // OK:只能当作 Object

3. 协变和逆变结合的设计

我们设计一个通用的数据处理流水线,既能从数据源读取订单,又能将订单传递给处理器。

完整实现:

public static <T> void processPipeline(
    List<? extends T> source, // 协变:只读数据源
    List<? super T> target    // 逆变:只写目标
) {
    for (T item : source) {
        System.out.println("读取订单:" + ((Order) item).getId());
        target.add(item); // 将订单传递到目标列表
    }
}

调用示例:

List<RegularOrder> regularOrders = List.of(new RegularOrder("R001"), new RegularOrder("R002"));
List<Order> allOrders = new ArrayList<>();

processPipeline(regularOrders, allOrders);

System.out.println("处理后的订单数:" + allOrders.size());

结果输出:

读取订单:R001
读取订单:R002
处理后的订单数:2

总结:协变与逆变的最佳场景

  • 协变(? extends T

    • 适合只读操作,数据来源多样化。
    • 典型场景:数据采集、读取列表内容。
  • 逆变(? super T

    • 适合只写操作,数据目标灵活多样。
    • 典型场景:数据存储、操作父类容器。
  • 协变与逆变结合

    • 适合需要“读取 + 写入”分工明确的场景,如数据流传输、数据转换。

用协变和逆变设计代码,不仅让代码更灵活安全,还能显著提升复用性和可维护性!

推荐阅读文章

  • 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)
  • 如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系
  • HTTP、HTTPS、Cookie 和 Session 之间的关系
  • 什么是 Cookie?简单介绍与使用方法
  • 什么是 Session?如何应用?
  • 使用 Spring 框架构建 MVC 应用程序:初学者教程
  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误
  • 如何理解应用 Java 多线程与并发编程?
  • 把握Java泛型的艺术:协变、逆变与不可变性一网打尽
  • Java Spring 中常用的 @PostConstruct 注解使用总结
  • 如何理解线程安全这个概念?
  • 理解 Java 桥接方法
  • Spring 整合嵌入式 Tomcat 容器
  • Tomcat 如何加载 SpringMVC 组件
  • “在什么情况下类需要实现 Serializable,什么情况下又不需要(一)?”
  • “避免序列化灾难:掌握实现 Serializable 的真相!(二)”
  • 如何自定义一个自己的 Spring Boot Starter 组件(从入门到实践)
  • 解密 Redis:如何通过 IO 多路复用征服高并发挑战!
  • 线程 vs 虚拟线程:深入理解及区别
  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别
  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!
  • “打破重复代码的魔咒:使用 Function 接口在 Java 8 中实现优雅重构!”
  • Java 中消除 If-else 技巧总结
  • 线程池的核心参数配置(仅供参考)
  • 【人工智能】聊聊Transformer,深度学习的一股清流(13)
  • Java 枚举的几个常用技巧,你可以试着用用

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

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

相关文章

2024年11月21日Github流行趋势

项目名称&#xff1a;twenty 项目维护者&#xff1a;charlesBochet, lucasbordeau, Weiko, FelixMalfait, bosiraphael项目介绍&#xff1a;正在构建一个由社区支持的现代化Salesforce替代品。项目star数&#xff1a;21,798项目fork数&#xff1a;2,347 项目名称&#xff1a;p…

VSCode汉化教程【简洁易懂】

我们安装完成后默认是英文界面。 找到插件选项卡&#xff0c;搜索“Chinese”&#xff0c;找到简体&#xff08;更具你的需要&#xff09;&#xff08;Microsoft提供&#xff09;Install。 安装完成后选择Change Language and Restart。

Leetcode 生命游戏

以下是上述Java代码的算法思想及其逻辑的中文解释&#xff1a; 算法思想 这段代码实现了LeetCode第289题“生命游戏”的解决方案。核心思想是&#xff1a; 利用原地修改的方式&#xff08;in-place&#xff09;存储下一状态的变化&#xff1a; 通过引入额外的状态值&#xff0…

C++【面试重要题目】 只出现一次的数字的集合.

文章目录 前言一、前提要点补充二、题集总结 前言 本篇笔者将会对 cpp 中比较有意思的类型题目进行细致讲解 . 这类题同时也是面试中比较重要的算法题 , 其算法思想需要学者掌握. 以下题目均来自力扣 一、前提要点补充 ● 几个运用运算符 因为笔者介绍的题目均会用到二进制…

麒麟部署一套NFS服务器,用于创建网络文件系统

一、服务端共享目录 在本例中,kyserver01(172.16.200.10)作为客户端,创建一个目录/testdir并挂载共享目录;kyserver02(172.16.200.11)作为服务端,创建一个共享目录/test,设置为读写权限,要求客户端使用root登录时映射为nobody用户、非root登录时保持不变。 服务端启…

VBA技术资料MF228:移动形状并覆盖某单元格区域

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

Python 数据分析核心库大全!

&#xff08;欢迎关注我的视频号&#xff09; &#x1f447;我的小册 45章教程:(小白零基础用Python量化股票分析小册) ,原价299&#xff0c;限时特价2杯咖啡&#xff0c;满100人涨10元。 大家好&#xff01;我是菜鸟哥&#xff01; 今天我们来聊点干货&#xff1a;Python 数据…

跨境出海安全:如何防止PayPal账户被风控?

今天咱们聊聊那些让人头疼的事儿——PayPal账户被风控。不少跨境电商商家反馈&#xff0c;我们只是想要安安静静地在网上做个小生意&#xff0c;结果不知道为什么&#xff0c;莫名其妙账户就被冻结了。 但其实每个封禁都是有原因的&#xff0c;今天就来给大家分享分享可能的原…

39页PDF | 毕马威_数据资产运营白皮书(限免下载)

一、前言 《毕马威数据资产运营白皮书》探讨了数据作为新型生产要素在企业数智化转型中的重要性&#xff0c;提出了数据资产运营的“三要素”&#xff08;组织与意识、流程与规范、平台与工具&#xff09;和“四重奏”&#xff08;数据资产盘点、评估、治理、共享&#xff09;…

数据科学与SQL:组距分组分析 | 区间分布问题

目录 0 问题描述 1 数据准备 2 问题分析 3 小结 0 问题描述 绝对值分布分析也可以理解为组距分组分析。对于某个指标而言&#xff0c;一个记录对应的指标值的绝对值&#xff0c;肯定落在所有指标值的绝对值的最小值和最大值构成的区间内&#xff0c;根据一定的算法&#x…

使用 PyTorch-BigGraph 构建和部署大规模图嵌入的完整教程

当涉及到图数据时&#xff0c;复杂性是不可避免的。无论是社交网络中的庞大互联关系、像 Freebase 这样的知识图谱&#xff0c;还是推荐引擎中海量的数据量&#xff0c;处理如此规模的图数据都充满挑战。 尤其是当目标是生成能够准确捕捉这些关系本质的嵌入表示时&#xff0c;…

23种设计模式-模板方法(Template Method)设计模式

文章目录 一.什么是模板方法模式&#xff1f;二.模板方法模式的特点三.模板方法模式的结构四.模板方法模式的应用场景五.模板方法模式的优缺点六.模板方法模式的C实现七.模板方法模式的JAVA实现八.代码解析九.总结 类图&#xff1a; 模板方法设计模式类图 一.什么是模板方法模…

.net的winfrom程序 窗体透明打开窗体时出现在屏幕右上角

窗体透明&#xff0c; 将Form的属性Opacity&#xff0c;由默认的100% 调整到 80%(尽量别低于50%)&#xff0c;这个数字越小越透明&#xff01; 打开窗体时出现在屏幕右上角 //构造函数 public frmCalendarList() {InitializeComponent();//打开窗体&#xff0c;窗体出现在屏幕…

DRNN 神经网络的Jacobian 信息辨识

DRNN 神经网络的 Jacobian 信息辨识 1. 基本原理 Jacobian 矩阵用于描述多输入多输出系统中输入和输出之间的偏导关系&#xff0c;其形式为&#xff1a; 对于 DRNN&#xff08;Dynamic Recurrent Neural Network&#xff09;&#xff0c;其动态特性使得 y(t)\mathbf{y}(t)y(t…

iptables网络安全服务详细使用

iptables防火墙概念说明 开源的基于数据包过滤的网络安全策略控制工具。 centos6.9 --- 默认防火墙工具软件iptables centos7 --- 默认防火墙工具软件firewalld&#xff08;zone&#xff09; iptables主要工作在OSI七层的二、三、四层&#xff0c;如果重新编译内核&…

《DAMA 数据管理知识体系指南》读书笔记 - 第 2 章 数据处理伦理

文章目录 1. 章节概述2. 核心概念与定义3. 重要方法与实践步骤4. 理论与实际结合5. 重点6. 理解与记忆要点7. 复习思考题标题图——书籍图片 WPS AI生成的XMind链接&#xff08;不用要源文件&#xff0c;下载不了&#xff09;&#xff1a; 【金山文档 | WPS云文档】 第2章 数据…

《线性代数的本质》

之前收藏的一门课&#xff0c;刚好期末复习&#xff0c;顺便看一看哈哈 课程链接&#xff1a;【线性代数的本质】合集-转载于3Blue1Brown官方双语】 向量究竟是什么 线性代数中最基础、最根源的组成部分就是向量&#xff0c;需要先明白什么是向量 不同专业对向量的看法 物理专…

AI 大模型如何重塑软件开发流程?——技术革新与未来展望

人工智能的蓬勃发展为许多领域注入了强劲动力&#xff0c;而在软件开发这一关键技术领域&#xff0c;AI 大模型的应用正在彻底改变传统流程。从代码自动生成到智能测试&#xff0c;再到协同开发和流程优化&#xff0c;AI 正逐步成为软件开发者的得力助手&#xff0c;也推动企业…

三季度业绩亮点多元,宝尊全域经营走向破茧成蝶

电商行业的变革从未停止&#xff0c;始终反映着网络消费和品牌发展的趋势&#xff0c;以及未来的想象空间&#xff0c;因此令赛道上的相关公司备受关注。 那么&#xff0c;当前赛道正在发生哪些变化&#xff1f;11月21日&#xff0c;行业龙头宝尊电商发布截至2024年9月30日的2…

机器学习day7-线性回归3、逻辑回归、聚类、SVC

7欠拟合与过拟合 1.欠拟合 模型在训练数据上表现不佳&#xff0c;在新的数据上也表现不佳&#xff0c;常发生在模型过于简单无法处理数据中的复杂模式时。 特征&#xff1a; 训练误差较高 测试误差也高 模型过于简化&#xff0c;不能充分学习训练数据中的模式 2.过拟合 …