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

通用静态错误处理函数实现及代码复用模式咨询

通用错误处理的代码复用方案

Great question! When all your exceptions follow the same handling pattern (log and rethrow), you absolutely can eliminate repetitive try/catch blocks using either higher-order functions (a functional programming approach) or the Decorator Pattern (an object-oriented design pattern). Let’s break both down with practical examples.

1. Higher-Order Functions (Functional Approach)

If your language supports lambdas or function references (like Java 8+, Python, JavaScript, etc.), this is the most concise solution. You’ll create a generic utility function that wraps your data access logic, handling the try/catch, logging, and rethrowing in one place.

Example (Java):

// Define a functional interface to represent any data access operation
@FunctionalInterface
public interface DataAccessOp<T> {
    T run() throws Exception;
}

// Static utility class with the shared error handling logic
public class DataAccessErrorHandler {
    private static final Logger logger = LoggerFactory.getLogger(DataAccessErrorHandler.class);

    public static <T> T handle(DataAccessOp<T> operation) {
        try {
            return operation.run();
        } catch (Exception e) {
            // Log the full exception stack trace for debugging
            logger.error("Data access operation failed", e);
            // Rethrow (wrap in a runtime exception if needed, or throw the original)
            throw new RuntimeException("Data access failure", e);
        }
    }
}

// Usage in your data access methods
public class UserRepository {
    public User getById(Long userId) {
        return DataAccessErrorHandler.handle(() -> {
            // Your actual data access logic (e.g., JDBC, ORM call)
            return jdbcTemplate.queryForObject("SELECT * FROM users WHERE id = ?", new UserRowMapper(), userId);
        });
    }

    public void save(User user) {
        DataAccessErrorHandler.handle(() -> {
            jdbcTemplate.update("INSERT INTO users (id, name) VALUES (?, ?)", user.getId(), user.getName());
            return null; // Placeholder for void operations
        });
    }
}

This way, every data access method only focuses on its core logic—all error handling lives in the single handle function. If you ever need to adjust the logging format or exception wrapping, you only change one place.

2. Decorator Pattern (Object-Oriented Approach)

If you prefer an OOP style, the Decorator Pattern lets you wrap your data access implementation with a decorator that adds error handling behavior without modifying the original class.

Example (Java):

// Base interface for all data access operations
public interface UserDataAccess {
    User getById(Long userId) throws Exception;
    void save(User user) throws Exception;
}

// The original implementation with no error handling
public class DefaultUserDataAccess implements UserDataAccess {
    @Override
    public User getById(Long userId) throws Exception {
        return jdbcTemplate.queryForObject("SELECT * FROM users WHERE id = ?", new UserRowMapper(), userId);
    }

    @Override
    public void save(User user) throws Exception {
        jdbcTemplate.update("INSERT INTO users (id, name) VALUES (?, ?)", user.getId(), user.getName());
    }
}

// Decorator that adds error handling
public class ErrorHandlingUserDataAccess implements UserDataAccess {
    private final UserDataAccess delegate;
    private final Logger logger = LoggerFactory.getLogger(ErrorHandlingUserDataAccess.class);

    public ErrorHandlingUserDataAccess(UserDataAccess delegate) {
        this.delegate = delegate;
    }

    @Override
    public User getById(Long userId) {
        try {
            return delegate.getById(userId);
        } catch (Exception e) {
            logger.error("Failed to fetch user with ID: {}", userId, e);
            throw new RuntimeException("User fetch failed", e);
        }
    }

    @Override
    public void save(User user) {
        try {
            delegate.save(user);
        } catch (Exception e) {
            logger.error("Failed to save user: {}", user.getId(), e);
            throw new RuntimeException("User save failed", e);
        }
    }
}

// Usage
UserDataAccess dataAccess = new ErrorHandlingUserDataAccess(new DefaultUserDataAccess());
User user = dataAccess.getById(1L);

The decorator wraps your original data access object, intercepting each method call to apply the shared error handling. This is great if you have multiple methods in your data access interface and want to apply the same logic to all of them.

Key Takeaway

Both approaches achieve the same goal: separating cross-cutting concerns (error handling) from your core business logic. This eliminates repetitive try/catch blocks, makes your code cleaner, and centralizes error handling logic so you can update it easily.

Pick the approach that aligns best with your language and coding style—higher-order functions are more lightweight for simple cases, while decorators offer more flexibility for complex OOP hierarchies.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:38:47