使用Chain的Builder方法代替有超多参数的构造方法

在面对具有大量参数的构造函数时,采用Builder模式及method chaining可以显著提高代码的可读性和可维护性。通过实例展示如何利用此模式创建对象,并强调这种方式能够使每个参数的作用更为明确。
我们有时候会遇到一些有超多参数的构造函数。其实对于日渐复杂的类来说,这种情况并不少见。使用Builder和一些method chain的改造,可以使我们的代码看起来更加DSL化。

Car car = CarBuilder.buildCar(CarType.MINI).engine(CarEngine.CVTT).size(3.15).build();

这样的方法比起原来的

Car car = new Car(CarType.MINI,CarEngine.CVTT,3.15);

更能确切地知道每个参数是用来干什么的,程序也更加容易读懂。
<think>我们有一个包含多个参数的HashMap,现在需要将其改为对象。这样做的优点包括: 1. 类型安全:避免在字符串中硬编码键名,减少拼写错误 2. 可维护性:当参数增减时,只需修改对象结构 3. 清晰性:通过对象属性名明确参数含义 原始代码中,我们构建了一个名为`params`的HashMap,其中包含多个键值对。我们可以将其重构为一个POJO(Plain Old Java Object)类。 ### 重构步骤: 1. 创建一个新的类,比如`DocumentUploadParams`,包含所有参数作为字段。 2. 为每个字段提供gettersetter(或者使用Lombok简化)。 3. 在需要的地方实例化该对象并设置属性值。 4. 使用该对象生成JSON字符串。 ### 示例代码: #### 定义参数对象 ```java public class DocumentUploadParams { private String language; private String isConfigurationItem; private String isProject; private String docEncode; private String securities; private String filePath; private String fileName; private String docOwner; private String userName; private String name; // 构造函数(可选) public DocumentUploadParams() { } // Getters and Setters public String getLanguage() { return language; } public void setLanguage(String language) { this.language = language; } // ... 其他字段的gettersetter // 注意:这里也可以使用Lombok的@Data注解自动生成getter/setter等方法 } ``` #### 重构后的调用代码 ```java // 创建参数对象代替HashMap DocumentUploadParams params = new DocumentUploadParams(); params.setLanguage("中文"); params.setIsConfigurationItem("false"); params.setIsProject("true"); params.setDocEncode("offering"); params.setSecurities("1"); params.setFilePath(folderPath); params.setFileName(fileName + getSrNo(srNo) + FILE_EXTENSION); params.setDocOwner(userName); params.setUserName(userName); params.setName(fileName + getSrNo(srNo)); // 将对象转换为JSON字符串 String jsonParams = JSONObject.toJSONString(params); // 进行URL编码 String docInfos = URLEncoder.encode(jsonParams, StandardCharsets.UTF_8); // 后续代码不变 HashMap<String, String> headers = getHeaders(APPLICATION_OCTET_STREAM); headers.put("docInfo", docInfos); // ... 继续后续操作 ``` ### 使用Lombok简化 如果项目中引入了Lombok,可以简化POJO类的定义: ```java import lombok.Data; @Data public class DocumentUploadParams { private String language; private String isConfigurationItem; private String isProject; private String docEncode; private String securities; private String filePath; private String fileName; private String docOwner; private String userName; private String name; } ``` 使用`@Data`注解后,Lombok会自动生成getter、setter、toString等方法。 ### 重构优势: 1. **类型安全**:每个字段都有明确的类型,而不是全部使用String。 2. **减少错误**:避免在字符串键名中拼写错误。 3. **易于扩展**:添加或删除参数时,只需修改POJO类,调用处通过setter设置,逻辑更清晰。 4. **可读性**:代码更易于理解维护。 ### 注意事项: 1. JSON序列化库(如Fastjson)需要能够将对象属性正确序列化。通常,这些库通过getter方法或字段反射来序列化。 2. 如果某些字段可以为空,确保在序列化时处理空值(根据需求决定是否序列化空值字段)。 3. 如果参数结构可能变化,考虑使用构建器模式或创建必要的构造函数来简化对象创建。 ### 完整重构示例: ```java // 使用Lombok的POJO @Data public class DocumentUploadParams { private String language = "中文"; // 可以设置默认值 private String isConfigurationItem; private String isProject; private String docEncode; private String securities; private String filePath; private String fileName; private String docOwner; private String userName; private String name; } // 在代码中 DocumentUploadParams params = new DocumentUploadParams(); params.setIsConfigurationItem("false"); params.setIsProject("true"); params.setDocEncode("offering"); params.setSecurities("1"); params.setFilePath(folderPath); params.setFileName(fileName + getSrNo(srNo) + FILE_EXTENSION); params.setDocOwner(userName); params.setUserName(userName); params.setName(fileName + getSrNo(srNo)); // 如果某些字段有默认值,可以省略设置(比如language已经有默认值"中文") ``` ### 进一步优化:构建器模式 如果参数很多,可以考虑使用构建器模式来创建参数对象,避免过长的setter调用。例如: ```java DocumentUploadParams params = DocumentUploadParams.builder() .isConfigurationItem("false") .isProject("true") .docEncode("offering") .securities("1") .filePath(folderPath) .fileName(fileName + getSrNo(srNo) + FILE_EXTENSION) .docOwner(userName) .userName(userName) .name(fileName + getSrNo(srNo)) .build(); ``` 在POJO类中添加构建器(Lombok同样支持): ```java @Data @Builder public class DocumentUploadParams { // ... 字段同上 } ``` 这样代码将更加简洁。 §§相关问题§§: 1. 在Java中,使用POJO代替HashMap作为数据传输对象有什么优缺点? 2. 如何确保POJO在序列化为JSON时符合特定的命名规范(例如驼峰转下划线)? 3. 使用Lombok的@Builder注解时,如何设置某些字段的默认值? 4. 如果参数需要动态扩展(例如允许任意自定义键值对),如何设计POJO结构? </think>是的,完全可以将 `HashMap<String, String>` 替换为自定义对象(POJO)。这样做有以下几个优点: 1. **类型安全**:避免字符串键名拼写错误 2. **可维护性**:字段增减只需修改对象结构 3. **可读性**:明确表达参数含义 4. **验证能力**:可在对象中添加校验逻辑 5. **扩展性**:方便添加默认值方法 以下是重构方案: ### 1. 创建参数对象(POJO) ```java import java.io.Serializable; public class DocumentUploadParams implements Serializable { private String language = "中文"; // 设置默认值 private String isConfigurationItem = "false"; private String isProject; private String docEncode = "offering"; private String securities = "1"; private String filePath; private String fileName; private String docOwner; private String userName; private String name; // 构造器(根据需要添加) public DocumentUploadParams(String filePath, String fileName, String docOwner, String userName, String name) { this.filePath = filePath; this.fileName = fileName; this.docOwner = docOwner; this.userName = userName; this.name = name; } // Getters and Setters(必须) public String getLanguage() { return language; } public void setLanguage(String language) { this.language = language; } // 其他字段的getter/setter... // 自定义方法示例 public String generateFullFileName(String srNo, String fileExtension) { return fileName + getSrNo(srNo) + fileExtension; } private String getSrNo(String srNo) { // 原getSrNo方法的实现 return "_" + srNo; // 示例实现 } } ``` ### 2. 重构后的调用代码 ```java // 使用POJO代替HashMap DocumentUploadParams params = new DocumentUploadParams( folderPath, fileName, userName, userName, fileName ); // 设置需要覆盖的默认值(可选) params.setIsProject("true"); // 自动生成文件名(使用对象内部方法) String fullFileName = params.generateFullFileName(srNo, FILE_EXTENSION); params.setFileName(fullFileName); // 序列化为JSON String jsonParams = JSONObject.toJSONString(params); String docInfos = URLEncoder.encode(jsonParams, StandardCharsets.UTF_8); // 后续逻辑不变 HashMap<String, String> headers = getHeaders(APPLICATION_OCTET_STREAM); headers.put("docInfo", docInfos); try { invoker.invoke(CubeRequest.builder() .headers(headers) .service("dboxPush") .body(bytes) .method(HttpMethod.POST) .sgovToken() .build(), String.class); } catch (Exception e) { // 异常处理 } ``` ### 3. 使用 Lombok 简化 POJO(推荐) 如果项目支持 Lombok,可以大幅简化代码: ```java import lombok.Builder; import lombok.Data; import lombok.experimental.Accessors; @Data @Builder @Accessors(chain = true) // 支持链式调用 public class DocumentUploadParams { @Builder.Default private String language = "中文"; @Builder.Default private String isConfigurationItem = "false"; private String isProject; @Builder.Default private String docEncode = "offering"; @Builder.Default private String securities = "1"; private String filePath; private String fileName; private String docOwner; private String userName; private String name; // 自定义方法... } ``` 使用 Builder 模式初始化: ```java DocumentUploadParams params = DocumentUploadParams.builder() .filePath(folderPath) .fileName(fileName + getSrNo(srNo) + FILE_EXTENSION) .docOwner(userName) .userName(userName) .name(fileName + getSrNo(srNo)) .build(); ``` ### 4. JSON 序列化说明 1. **默认行为**: - FastJSON 默认使用字段名作为 JSON key - 字段顺序与声明顺序一致(开启 `Feature.OrderedField`) 2. **自定义序列化**: ```java @JSONField(name = "doc_owner", ordinal = 3) private String docOwner; @JSONField(serialize = false) // 排除字段 private transient String internalField; ``` ### 5. 完整重构示例(含请求逻辑) ```java public void uploadDocument(byte[] bytes, String folderPath, String fileName, String userName, String srNo) throws Exception { // 1. 构建参数对象 DocumentUploadParams params = new DocumentUploadParams( folderPath, fileName, userName, userName, fileName ).setFileName(fileName + getSrNo(srNo) + FILE_EXTENSION); // 2. 序列化并编码 String docInfos = URLEncoder.encode( JSONObject.toJSONString(params, SerializerFeature.WriteMapNullValue), StandardCharsets.UTF_8 ); // 3. 准备请求 Map<String, String> headers = new HashMap<>(getHeaders(APPLICATION_OCTET_STREAM)); headers.put("docInfo", docInfos); // 4. 发送请求 Response response = invoker.invoke( CubeRequest.builder() .headers(headers) .service("dboxPush") .body(bytes) .method(HttpMethod.POST) .sgovToken() .build(), Response.class ); // 5. 处理响应 if (!response.isSuccess()) { throw new UploadException("Upload failed: " + response.getError()); } } ``` ### 重构的优点: 1. **类型安全**:编译器检查字段类型 2. **代码自文档化**:字段名直接说明用途 3. **减少错误**:避免字符串键名拼写错误 4. **可重用性**:可在多处复用参数对象 5. **可测试性**:参数对象可单独测试 6. **默认值支持**:初始化时自动设置默认值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值