You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

重构存在差异分支的多方法if语句块问题咨询

Handling Refactoring with Shared Logic + Minor Variations

Great question—this is a super common refactoring pickle: you want to DRY up repetitive error handling, but tiny context-specific differences are getting in the way. Let’s break down a few solid approaches that balance reuse and flexibility:

1. Default Mapping + Local Overrides

This is my go-to for most cases where 90% of the logic is shared, and only a few error codes have different mappings.

First, define a global default mapping that captures the majority of your error code to OutErrorType mappings:

// Default mapping for most methods
private static final Map<Integer, OutErrorType> DEFAULT_ERR_MAP = Map.of(
    IN_ERR_CONST_1, OutErrorType.TYPE_A,
    IN_ERR_CONST_2, OutErrorType.TYPE_A, // Default behavior
    IN_ERR_CONST_3, OutErrorType.TYPE_A,
    // ... add all other shared mappings
    IN_ERR_CONST_9, OutErrorType.TYPE_B,
    IN_ERR_CONST_10, OutErrorType.TYPE_B
);

Then create a shared helper method that accepts an optional override map (for the edge cases):

private void handleErrorCode(int errCode, Map<Integer, OutErrorType> overrideMap) {
    // Merge default and override maps—overrides take priority
    Map<Integer, OutErrorType> combinedMap = new HashMap<>(DEFAULT_ERR_MAP);
    combinedMap.putAll(overrideMap);

    OutErrorType outType = combinedMap.get(errCode);
    if (outType != null) {
        throw new CustomException(outType);
    }
    // Optional: handle unrecognized error codes here (e.g., throw a generic exception)
}

Now each method only needs to pass in the differences:

// Method with default behavior
public void processPayment(int errCode) {
    // ... your business logic
    handleErrorCode(errCode, Collections.emptyMap());
}

// Method where IN_ERR_CONST_2 maps to TYPE_B instead
public void processRefund(int errCode) {
    // ... your business logic
    handleErrorCode(errCode, Map.of(IN_ERR_CONST_2, OutErrorType.TYPE_B));
}

Pros: Keeps duplication to a minimum, easy to update shared mappings, and variations are explicit.
Cons: Not ideal if variations involve more than just swapping error types (e.g., extra validation steps).

2. Strategy Pattern for Flexible Variations

If you anticipate more variations down the line (or some methods need extra logic beyond just mapping), the strategy pattern is a clean, scalable solution.

First, define an interface for your error mapping strategy:

interface ErrorMappingStrategy {
    OutErrorType resolveOutErrorType(int errCode);
}

Implement a default strategy for the common case:

class DefaultErrorStrategy implements ErrorMappingStrategy {
    @Override
    public OutErrorType resolveOutErrorType(int errCode) {
        return switch(errCode) {
            case IN_ERR_CONST_1, IN_ERR_CONST_2, IN_ERR_CONST_3 -> OutErrorType.TYPE_A;
            case IN_ERR_CONST_9, IN_ERR_CONST_10 -> OutErrorType.TYPE_B;
            default -> null; // Or handle unknown errors
        };
    }
}

Then create a specialized strategy for methods with variations—extend the default to reuse logic:

class RefundErrorStrategy extends DefaultErrorStrategy {
    @Override
    public OutErrorType resolveOutErrorType(int errCode) {
        // Override the specific case
        if (errCode == IN_ERR_CONST_2) {
            return OutErrorType.TYPE_B;
        }
        // Delegate to default for all other cases
        return super.resolveOutErrorType(errCode);
    }
}

Update your helper method to accept a strategy:

private void handleErrorCode(int errCode, ErrorMappingStrategy strategy) {
    OutErrorType outType = strategy.resolveOutErrorType(errCode);
    if (outType != null) {
        throw new CustomException(outType);
    }
}

And call it from your methods:

public void processPayment(int errCode) {
    // ...
    handleErrorCode(errCode, new DefaultErrorStrategy());
}

public void processRefund(int errCode) {
    // ...
    handleErrorCode(errCode, new RefundErrorStrategy());
}

Pros: Extensible (add new strategies without modifying existing code), great for complex variations, and keeps logic organized.
Cons: Adds a bit more boilerplate—only worth it if you expect future changes.

3. Parameterized Control for Minimal Differences

If you only have one or two tiny variations (like just the IN_ERR_CONST_2 case), you can keep things ultra-simple with a boolean parameter:

private void handleErrorCode(int errCode, boolean mapConst2ToTypeB) {
    OutErrorType outType;

    // Handle the special case first
    if (errCode == IN_ERR_CONST_2 && mapConst2ToTypeB) {
        outType = OutErrorType.TYPE_B;
    } else {
        // Default mapping logic
        outType = switch(errCode) {
            case IN_ERR_CONST_1, IN_ERR_CONST_2, IN_ERR_CONST_3 -> OutErrorType.TYPE_A;
            case IN_ERR_CONST_9, IN_ERR_CONST_10 -> OutErrorType.TYPE_B;
            default -> null;
        };
    }

    if (outType != null) {
        throw new CustomException(outType);
    }
}

Call it like this:

public void processPayment(int errCode) {
    handleErrorCode(errCode, false);
}

public void processRefund(int errCode) {
    handleErrorCode(errCode, true);
}

Pros: No extra classes or maps—super simple for minimal variations.
Cons: Avoid this if you think more variations will pop up—too many boolean parameters will make the method messy and hard to maintain.


Which Approach to Choose?

  • Default Mapping + Local Overrides: Best for most cases where variations are just a few key swaps.
  • Strategy Pattern: Perfect if you anticipate future changes or need more complex logic variations.
  • Parameterized Control: Only use this for extremely minimal, one-off differences.

内容的提问来源于stack exchange,提问作者l0r3nz4cc10

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 21:47:29