对接外卖餐饮美食API接口:Java用Builder模式优化复杂请求参数的构建逻辑

华为OD机试真题 2026.11.4. 新系统 【河流水系流量评估】 华为OD机试真题 新系统【河流水系流量评估】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题 【河流水系流量评估】多语言题解。 阅读详情

对接外卖餐饮美食API接口:Java用Builder模式优化复杂请求参数的构建逻辑

在构建外卖餐饮美食类应用时,后端服务经常需要对接各类API接口,以获取丰富的菜品、商家和优惠信息。作为外卖霸王餐API唯一供给源头,同时也是外卖霸王餐CPS唯一取链源头,俱美开放平台提供了全面而强大的数据支持。然而,这些功能丰富的API往往伴随着复杂的请求参数。一个典型的查询请求可能包含地理位置、筛选条件、排序规则、分页信息等多个维度的参数,其中大部分还是可选的。

传统的对象创建方式,如重叠构造器模式或JavaBean模式,在处理这类复杂对象时会显得力不从心。重叠构造器会导致代码可读性差,而JavaBean模式则可能因对象状态不一致而引发线程安全问题。本文将探讨如何使用Builder(建造者)模式,以一种清晰、安全且高效的方式来构建这些复杂的API请求参数。

一、传统方式的困境:当参数变得复杂

假设我们需要向俱美开放平台发起一个查询附近美食的请求。这个请求可能需要包含经纬度、城市ID、美食分类、人均价格区间、排序方式以及分页信息。

如果使用JavaBean模式,代码可能如下所示:

package baodanbao.com.cn.api;

// 假设这是请求参数的DTO
public class FoodQueryRequest {
    private double latitude;
    private double longitude;
    private int cityId;
    private String category;
    private Integer minPrice;
    private Integer maxPrice;
    private String sortBy;
    private int page;
    private int pageSize;

    // 省略了大量的getter和setter方法
    public void setLatitude(double latitude) { this.latitude = latitude; }
    public void setLongitude(double longitude) { this.longitude = longitude; }
    // ... 其他setter
}

在业务代码中,调用方需要这样使用:

FoodQueryRequest request = new FoodQueryRequest();
request.setLatitude(30.2741);
request.setLongitude(120.1551);
request.setCityId(330100);
request.setCategory("火锅");
request.setMinPrice(50);
request.setMaxPrice(150);
request.setSortBy("sales");
request.setPage(1);
request.setPageSize(20);

这种方式存在几个明显的问题:

  1. 代码冗长:需要编写大量的setter调用。
  2. 对象状态不一致:在调用所有setter之前,request对象处于一个不完整、不合法的状态。
  3. 线程不安全:如果这个对象被多个线程共享,setter方法会破坏其状态。
  4. 可读性差:当参数众多时,很难一眼看出每个值的含义。
    在这里插入图片描述
二、Builder模式:优雅的解决方案

Builder模式的核心思想是将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。它通过一个内部的静态Builder类来逐步构建最终的对象。

下面是使用Builder模式重构后的FoodQueryRequest类:

package baodanbao.com.cn.api;

/**
 * 美食查询请求参数,使用Builder模式构建
 * @author baodanbao.com.cn
 */
public class FoodQueryRequest {
    // 必填参数
    private final double latitude;
    private final double longitude;
    private final int cityId;

    // 可选参数
    private final String category;
    private final Integer minPrice;
    private final Integer maxPrice;
    private final String sortBy;
    private final int page;
    private final int pageSize;

    // 私有构造器,强制使用Builder来创建对象
    private FoodQueryRequest(Builder builder) {
        this.latitude = builder.latitude;
        this.longitude = builder.longitude;
        this.cityId = builder.cityId;
        this.category = builder.category;
        this.minPrice = builder.minPrice;
        this.maxPrice = builder.maxPrice;
        this.sortBy = builder.sortBy;
        this.page = builder.page;
        this.pageSize = builder.pageSize;
    }

    // 静态内部类Builder
    public static class Builder {
        // 必填参数
        private final double latitude;
        private final double longitude;
        private final int cityId;

        // 可选参数,提供默认值
        private String category = "";
        private Integer minPrice;
        private Integer maxPrice;
        private String sortBy = "default";
        private int page = 1;
        private int pageSize = 20;

        // 构造器只接收必填参数
        public Builder(double latitude, double longitude, int cityId) {
            this.latitude = latitude;
            this.longitude = longitude;
            this.cityId = cityId;
        }

        // 为每个可选参数提供一个返回Builder自身的方法,实现链式调用
        public Builder category(String category) {
            this.category = category;
            return this;
        }

        public Builder priceRange(Integer min, Integer max) {
            this.minPrice = min;
            this.maxPrice = max;
            return this;
        }

        public Builder sortBy(String sortBy) {
            this.sortBy = sortBy;
            return this;
        }

        public Builder page(int page, int pageSize) {
            this.page = page;
            this.pageSize = pageSize;
            return this;
        }

        // build()方法用于创建最终的FoodQueryRequest对象
        public FoodQueryRequest build() {
            // 可以在这里添加参数校验逻辑
            if (minPrice != null && maxPrice != null && minPrice > maxPrice) {
                throw new IllegalArgumentException("最低价格不能高于最高价格");
            }
            return new FoodQueryRequest(this);
        }
    }

    // 省略getter方法
    public double getLatitude() { return latitude; }
    public double getLongitude() { return longitude; }
    public int getCityId() { return cityId; }
    public String getCategory() { return category; }
    // ... 其他getter
}
三、实战应用:构建API请求

现在,业务代码变得极其简洁和易读。调用方可以清晰地看到每个参数的含义,并且只设置自己关心的可选参数。

package baodanbao.com.cn.service;

import baodanbao.com.cn.api.FoodQueryRequest;
import org.springframework.stereotype.Service;

/**
 * 美食服务,负责调用俱美开放平台的API
 * @author baodanbao.com.cn
 */
@Service
public class FoodService {

    public void findNearbyFoods() {
        // 使用Builder模式构建请求参数
        FoodQueryRequest request = new FoodQueryRequest.Builder(30.2741, 120.1551, 330100)
                .category("火锅")
                .priceRange(50, 150)
                .sortBy("sales")
                .page(1, 20)
                .build();

        // 此时request对象已经完全构建好,且是不可变的(Immutable)
        // 可以安全地传递给API客户端进行调用
        // apiClient.queryFoods(request);
    }
}

通过采用Builder模式,我们不仅解决了复杂对象构建的难题,还获得了以下好处:

  • 代码可读性高:链式调用清晰地表达了构建意图。
  • 对象安全性高:最终创建的对象是不可变的,线程安全。
  • 灵活性强:调用方可以自由选择设置哪些可选参数。
  • 易于维护:当需要增加新的可选参数时,只需在Builder类中添加对应的方法即可,不影响现有代码。

这种优雅的设计模式,让对接像俱美开放平台这样功能丰富的API变得更加轻松和可靠。

本文著作权归 俱美开放平台 ,转载请注明出处!

SpringBoot+Vue+MySQL 高校学科竞赛平台 完整可运行版(源码+文档) 本项目基于SpringBoot+Vue+MySQL构建高校学科竞赛管理平台,覆盖学生、教师、领队教师、管理员四大角色,实现竞赛发布、报名、刷题、评分、公示等全流程闭环管理。系统架构清晰,技术主流,配套完整源码、数据库脚本、万字论文、开题报告、答辩PPT及部署文档,支持一键运行,适用于毕业设计、课程设计及院系二次开发,真正实现“开箱即用”。 阅读详情

相关推荐

AUTOSAR FEE 换页机制深度解析:从原理到实现逻辑

​​没有磨损均衡的EEPROM模拟,如同在沙地上建造城堡​​ ——AUTOSAR存储系统设计箴言

汽车电子软件领域知识分享 1338

InnoDB 内存结构总览:Change Buffer、AHI 与 Log Buffer

本文系统梳理InnoDB内存结构中的ChangeBuffer、Adaptive Hash Index(AHI)与LogBuffer。ChangeBuffer缓存二级索引页不在内存时的变更,减少随机IO,仅在页加载时合并;聚簇索引修改立即执行,因数据本身不可延后。AHI基于高频等值查询自动构建哈希索引,加速定位,仅支持等值操作。LogBuffer为redo log内存缓冲,配合磁盘日志实现崩溃恢复。三者均服务于性能优化,其中ChangeBuffer与AHI共享BufferPool空间,而LogBuffer独立

bksczm的博客 287

基于Dify构建银行智能客服:从意图识别到多RAG架构的实战解析

本文深入解析了如何利用Dify平台构建银行智能客服系统。从传统客服痛点出发,详细阐述了基于意图识别精准分类用户需求,并通过多RAG架构解决知识混淆问题,实现高效、准确的业务响应。文章重点介绍了结合工具调用实现业务流程自动化,并强调了数据本地化部署、内容安全过滤等银行级安全合规实践,为金融行业AI应用提供了实战指南。

yog99的博客 926

V8 机制、手写核心函数与 TypeScript 类型体操

或固定初始化(如数组先定长、对象先给全字段)保持类型与形状稳定;这些都比"换框架"更基础。只能处理纯数据(丢函数、Date、RegExp、循环引用报错)。生产级深拷贝要处理:原始值短路、循环引用、V8(Chrome / Node 的 JS 引擎)不是"解释一行跑一行"那么简单,它用。图:V8 执行流程——解释执行 + 热点优化,优化失败会 Deopt 回退。JS 内存自动管理,但"自动"不等于"不会漏"。是"固定间隔最多执行一次"。手写 Promise 是"懂异步"的试金石。是"停下后才执行最后一次",

qq_38468358的博客 346

BrepNet实战:5分钟搞定三维CAD模型的加工特征识别(附Python代码)

本文详细介绍了BrepNet在三维CAD模型加工特征识别中的实战应用,通过Python代码演示了从环境搭建到模型训练的全流程。BrepNet基于边界表示(BRep)的深度学习框架,能够高效识别加工特征,显著提升工业设计和智能制造领域的效率。文章还提供了性能优化和部署建议,帮助开发者快速实现AI驱动的几何特征识别。

weixin_29044713的博客 507

SpringBoot整合海康SDK实战:从设备初始化到PS流录像转MP4全流程(附避坑指南)

本文详细介绍了SpringBoot整合海康SDK的完整实战流程,涵盖设备初始化、通道管理、录像检索与下载。针对海康设备生成的PS流录像文件无法直接播放的痛点,重点解析了如何利用FFmpeg高效、无损地将其转换为通用的MP4格式,并提供了关键的避坑指南和性能优化建议。

chair的专栏 764

Java EE 进阶:8.MyBatis 操作数据库(入门)(第一弹)

Java EE 进阶:8.MyBatis 操作数据库(入门)(第一弹)

要努力去发光,而不是被照亮~ 129

一文搞懂蚁群算法Ant Colony Optimization(ACO)!!!(灵感起源+数学原理+代码实现+实战应用)

本文系统介绍了蚁群算法的原理与实现。首先从蚂蚁觅食行为出发,阐释了信息素正反馈机制如何引导群体找到最短路径。随后详细解析了算法的数学模型,包括状态转移规则和信息素更新机制。通过MATLAB代码演示了算法在旅行商问题(TSP)中的应用,展示了路径构建和优化的完整流程。最后讨论了算法的优势、局限性和实际应用场景。蚁群算法通过模拟生物智能,为解决复杂优化问题提供了一种高效方法,其核心在于信息素的正反馈机制与随机探索的平衡。

qq_42212808的博客 887

Spring Boot 数据源与 MyBatis(-Plus) 自定义配置详解

本文详解 Spring Boot 中单数据源环境下 HikariCP 与 MyBatis-Plus 的自定义配置。通过手动声明 SqlSessionFactory,实现下划线转驼峰、日志输出、一级缓存策略等精细化控制。结合 HikariCP 核心参数调优(如最大连接数、连接生命周期),确保高性能与稳定性。适用于仅需访问单一数据库的场景,避免多数据源复杂性,兼顾性能与可维护性。

BADAO_LIUMANG_QIZHI的博客 198

ConvNeXt 系列改进:二次创新 ConvNeXt:结合 RepVGG 结构重参数化,训练多分支、推理单路

2026年的视觉模型赛道呈现出一种有趣的“返璞归真”趋势——在Transformer狂飙数年之后,卷积网络正以全新的姿态回归。这其中,ConvNeXt无疑是纯卷积阵营中最耀眼的明星。从2022年Meta AI首次提出至今,ConvNeXt系列已经走过了近四年的演进之路,衍生出ConvNeXt V2、E-ConvNeXt等多个增强版本。ConvNeXt的7×7深度卷积带来了不错的感受野,却也埋下了推理效率的隐患。

ZXSXJ的博客 234

【音视频 ffmpeg 学习】 RTMP推流 mp4文件

3.当RTMP协议在互联网中传输数据的时候,消息会被拆分成更小的单元,称为消息块(Chunk)。1.RTMP(实时消息传输协议)是Adobe 公司开发的一个基于TCP的应用层协议。2.RTMP协议中基本的数据单元称为消息(Message)。下载地址:http://nginx.org/download。下载 rtmp模块 到nginx 模块下。安装nginx 和 rtmp模块。(1). linux 环境准备。下载nginx安装包。使用 vcl 播放流。

weixin_45397344的博客 2274

LeetCode Hot 100 二叉树专题(二)3 题(Java)

本篇文章共 3 题:543. 二叉树的直径、102. 二叉树的层序遍历、108. 将有序数组转换为二叉搜索树。 每道题都统一按「① 题目分析 & 解题思路 → ② 常见解法(附代码)及讲解 → ③ 知识点总结」的顺序组织;代码使用 Java 编写,节点定义沿用 LeetCode 默认的 TreeNode。

2401_88612756的博客 365

ABAP CDS 实体权限控制,从 DCL 到 PFCG 的完整运行逻辑

本文探讨了SAP S/4HANA开发中CDS View的权限控制机制。核心观点如下: CDS access control通过DCL语言实现数据实例级权限控制,而非替代传统PFCG权限体系,二者形成互补关系:PFCG控制功能入口权限,DCL控制数据可见性。 DDL定义数据结构,DCL定义访问规则。DCL通过角色映射将数据字段与PFCG授权对象关联,运行时自动将权限条件注入SQL查询,实现数据过滤。 访问控制行为特点: 无DCL role不会默认拒绝访问 权限检查通过减少结果集而非抛出错误实现 需配合@Acc

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 101

【从零理解 Spring AI · 12】MCP 的两种角色:做客户端还是做服务端

上一篇讲了 MCP 的概念:标准协议、三大角色、M+N 替代 M×N。

nice_lcj520的博客 499

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

JDK 下载安装:装完 Java 提示「不是内部或外部命令」?环境变量没配

JDK 是写 Java 程序必须装的东西。它包含运行 Java 的虚拟机(JRE)和编译 Java 的编译器(javac)——装了它,能跑、.java文件能编译成可执行程序。免费,学习和小规模生产都不花钱。

科小怪的博客 635

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

java框架大全

java框架大全

qq_39326137的博客 183

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Java 多态 学习笔记

多态是面向对象编程的重要特性,指同一操作作用于不同对象时产生不同行为。其核心在于“父类引用指向子类对象”,结合方法重写实现运行时动态绑定。多态使代码更灵活、可扩展,如用Person p = new Student();统一处理各类人员注册,无需修改调用逻辑。但多态无法直接调用子类特有方法,需通过instanceof判断并强制转换。编译时看左边(类型),运行时看右边(实际对象),实现解耦与维护便利。

AA_AA114514的博客 361

SecureRandom做随机源,这个Java随机字符串工具类有3个方法

本文分享一款JDK17环境下的Java随机字符串工具类,内置3个开箱即用的方法,全部采用SecureRandom加密安全随机源,不存在弱随机、可预测、取模偏差等问题。工具类支持默认62字符集随机串、纯数字随机串、自定义字符集随机串三种生成模式,支持Unicode码点级别的字符集处理,兼容Emoji等增补字符,边界处理严格,异常信息明确,适合验证码、邀请码、盐值、随机口令、短链码等场景,源码可直接复制使用。

Java后端 | AI智能体应用实战派 | 电脑技能行家 298

IDEA 简介:从零认识 IntelliJ IDEA

IDEA 全称,是由 JetBrains 公司开发的一款主流 Java 集成开发环境(IDE)。它集代码编辑、编译、调试、测试、版本控制、构建管理等功能于一体,被大量 Java 开发者视为日常开发的首选工具。所谓 IDE(Integrated Development Environment,集成开发环境),就是把写代码所需的各类工具整合到同一个界面中。相比只用文本编辑器加命令行编译,IDE 能显著减少重复操作,让开发者把精力集中在业务逻辑上。

ztI10的博客 151

Java实现批量线段相交检测(跨积判定+扫描线优化与踩坑复盘)

【代码】Java实现批量线段相交检测(跨积判定+扫描线优化与踩坑复盘)

m0_64476639的博客 328

ubuntu安装hadoop系统

本文详细介绍了基于VMware克隆虚拟机搭建三节点Hadoop分布式集群的全过程:使用同一Ubuntu镜像克隆出master、worker1、worker2三台虚拟机,依次配置主机名、固定IP(如192.168.82.10/11/12)、SSH服务及免密登录,确保节点间网络互通。随后安装Java,下载配置Hadoop并分发至各节点,最终初始化启动集群,验证其存储与计算功能,实现高效的大数据环境部署。

qq_43592674的博客 334

TRingBuffer两端都能增删(快递站版)

TRingBuffer 是一个支持两端增删、下标访问且容量动态增长的环形双端队列。它通过无符号索引的永不归零设计,利用减法自动模运算实现空满判断与元素计数,避免了传统环形缓冲浪费格子的问题。内部以票号(索引)标记首尾,扩容时重排元素为连续存储,保证 O(1) 操作与高缓存效率。虽不线程安全,但其高效性使其成为游戏开发中事件队列、命令缓冲等场景的理想选择。

u013768914的博客 227

Mac上装了最新版本的Android Studio,但是没找到jdk的设置选项也没找到jbr的目录

新版Android Studio(2025.3.1+)因三项变更导致常见问题:一、JDK设置移至“DaemonJVM criteria”,新项目默认自动探测或下载JDK;二、JBR目录改名为带版本号的jbr-21等,需进入.app/Contents/查看,或通过About窗口确认运行时;三、命令行缺adb因platform-tools未加入PATH,需在SDK Manager中勾选并配置~/.zshrc中的ANDROID_HOME及PATH。重装或清理残留可解决缺失问题,切勿手动设JAVA_HOME或安装冲

Programming is a highly artistic endeavor 355

Spring事务和事务传播机制

3. 可重复读(REPEATABLE READ): 事务不会读到其他事务对已有数据的修改, 即使其他事务已提交. 也就可以确保同⼀事务多次查询的结果⼀致, 但是其他事务新插⼊的数据, 是可以感知到的. 这也就引发了幻读问题. 可重复读, 是 MySQL 的默认事务隔离级别.p1事务可以认为是⽗事务, 嵌套事务是⼦事务. ⽗事务出现异常, ⼦事务也会回滚, ⼦事务出现异常, 如果不进⾏处理, 也会导致⽗事务回滚.

txxzjmzlh的博客 205

Java Arrays.asList 常见坑详解|UnsupportedOperationException、数组联动、基本类型 bug

解析 Arrays.asList 常见开发陷阱,演示 UnsupportedOperationException、底层数组引用共享、基本类型数组问题,区分 Arrays 内部 ArrayList 与 java.util.ArrayList,给出数组转 List 的各种场景正确代码。

weixin_42617033的博客 473

读懂 Dart Future:从 async/await 到并发等待

Dart 中的 Future 用于处理异步操作,如网络请求、文件读取等。它表示一次可能延迟完成的计算,成功时返回指定类型值(如 Future<String>),失败时抛出异常。通过 async/await 可以同步式编写异步代码,提升可读性。await 暂停当前函数执行,但不影响事件循环。Future.wait() 可并发等待多个异步任务,timeout() 设置超时限制,catchError() 处理错误。注意:async 不自动开启新线程,耗时计算仍可能阻塞主线程;避免丢弃未处理的 Future,必要时

侯仕奇的博客 356
上一篇: 构建高可用霸王餐CPS系统:Java后端用Guava RateLimiter实现第三方接口限流保护
下一篇: 省钱外卖CPS系统实战:Java用函数式编程简化多渠道返利规则的配置逻辑
吃喝不愁霸王餐APP开发者
博客等级 码龄2年 156粉丝 402原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值