设计模式问题:如何重构过度使用布尔参数的文件上传函数?
重构方案
1. 封装可变配置项,替换零散布尔参数
首先将所有控制执行逻辑的标志参数封装为独立的UploadConfig配置类,使用构造器模式(Builder)实现实例化,既保留参数默认值兼容旧调用,也大幅提升调用处的可读性:
// 配置类示例 public class UploadConfig { private final boolean ignoreAzure; private final boolean ignoreAws; private final boolean logToAirtable; private UploadConfig(Builder builder) { this.ignoreAzure = builder.ignoreAzure; this.ignoreAws = builder.ignoreAws; this.logToAirtable = builder.logToAirtable; } public static class Builder { // 默认值可根据通用场景设定 private boolean ignoreAzure = false; private boolean ignoreAws = false; private boolean logToAirtable = false; public Builder ignoreAzure(boolean val) { ignoreAzure = val; return this; } public Builder ignoreAws(boolean val) { ignoreAws = val; return this; } public Builder logToAirtable(boolean val) { logToAirtable = val; return this; } public UploadConfig build() { return new UploadConfig(this); } } // 仅提供getter方法,保证配置不可变 public boolean isIgnoreAzure() { return ignoreAzure; } public boolean isIgnoreAws() { return ignoreAws; } public boolean isLogToAirtable() { return logToAirtable; } }
改造后的方法签名如下,新增配置项时只需修改配置类,无需改动方法签名:
public ResponseObject uploadThing(long user_id, long location_id, byte[] file_bytes, UploadConfig config)
2. 拆分执行步骤,固定执行顺序
将原有函数内的每个功能段拆分为独立的步骤实现,统一实现UploadStep接口,内部自行判断是否需要执行:
public interface UploadStep { // 判断当前步骤是否需要执行 boolean shouldExecute(UploadConfig config); // 执行步骤逻辑 void execute(long userId, long locationId, byte[] fileBytes, UploadConfig config); } // 示例步骤:Azure上传 public class AzureUploadStep implements UploadStep { @Override public boolean shouldExecute(UploadConfig config) { return !config.isIgnoreAzure(); } @Override public void execute(long userId, long locationId, byte[] fileBytes, UploadConfig config) { // 原有Azure上传逻辑 } } // 其他步骤(AWS上传、Airtable日志等)同理实现
在uploadThing内部按要求的固定顺序维护步骤列表,遍历执行即可:
public ResponseObject uploadThing(long user_id, long location_id, byte[] file_bytes, UploadConfig config) { // 固定执行顺序,新增步骤只需在此处添加即可 List<UploadStep> steps = List.of( new AzureUploadStep(), new AwsUploadStep(), new AirtableLogStep() ); for (UploadStep step : steps) { if (step.shouldExecute(config)) { step.execute(user_id, location_id, file_bytes, config); } } // 原有返回逻辑 return new ResponseObject(); }
3. 调用示例
调用处代码可读性大幅提升,无需记忆参数顺序:
// 原有调用:ro = uploadThing(user_id, org_id, file_bytes, true, false, true) // 改造后调用 UploadConfig config = new UploadConfig.Builder() .ignoreAzure(true) .ignoreAws(false) .logToAirtable(true) .build(); ro = uploadThing(user_id, org_id, file_bytes, config);
4. 可选优化:封装场景化快捷方法
如果存在固定的通用调用场景,可以额外封装对应场景的静态方法,进一步降低调用方的使用成本:
// 示例:内部系统上传场景,默认忽略AWS、打Airtable日志 public static ResponseObject uploadForInternal(long user_id, long location_id, byte[] file_bytes) { UploadConfig config = new UploadConfig.Builder() .ignoreAws(true) .logToAirtable(true) .build(); return uploadThing(user_id, location_id, file_bytes, config); }
调用方直接调用uploadForInternal即可,完全不需要关心内部配置细节,意图清晰。
内容的提问来源于stack exchange,提问作者Orolo
相关产品推荐
相关产品推荐

