对接外卖餐饮美食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);
这种方式存在几个明显的问题:
- 代码冗长:需要编写大量的setter调用。
- 对象状态不一致:在调用所有setter之前,
request对象处于一个不完整、不合法的状态。 - 线程不安全:如果这个对象被多个线程共享,setter方法会破坏其状态。
- 可读性差:当参数众多时,很难一眼看出每个值的含义。

二、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变得更加轻松和可靠。
本文著作权归 俱美开放平台 ,转载请注明出处!
1338



被折叠的 条评论
为什么被折叠?



