代码重构的15个小技巧


代码重构的15个小技巧

前言

相信很多小伙伴在日常工作中都会遇到这样的情况:接手了一个历史项目,代码像一团乱麻。

或者自己写的代码随着业务的不断迭代,变得越来越臃肿难以维护。

这时候,代码重构就显得尤为重要了。

那么,如何进行高效的代码重构呢?

这篇文章我跟大家大家一起聊聊15个实用的代码重构技巧,希望对你会有所帮助。

1. 提取方法

有些小伙伴在工作中可能会写出这样的代码:一个方法几百行,里面包含了各种业务逻辑。

这样的代码不仅难以阅读,也难以维护和测试。

重构前:

public void processOrder(Order order) {
    // 验证订单
    if (order == null) {
        throw new IllegalArgumentException("订单不能为空");
    }
    if (order.getItems() == null || order.getItems().isEmpty()) {
        throw new IllegalArgumentException("订单项不能为空");
    }
    if (order.getCustomer() == null) {
        throw new IllegalArgumentException("客户信息不能为空");
    }
    
    // 计算订单总价
    double total = 0;
    for (OrderItem item : order.getItems()) {
        double price = item.getPrice();
        int quantity = item.getQuantity();
        total += price * quantity;
    }
    
    // 应用折扣
    if (order.getCustomer().isVip()) {
        total = total * 0.9;
    }
    
    // 保存订单
    order.setTotal(total);
    orderRepository.save(order);
    
    // 发送通知
    String message = "订单" + order.getId() + "已处理,总价:" +  total;
    emailService.sendEmail(order.getCustomer().getEmail(), "订单处理通知", message);
    smsService.sendSms(order.getCustomer().getPhone(), message);
}

重构后:

public void processOrder(Order order) {
    validateOrder(order);
    double total = calculateOrderTotal(order);
    total = applyDiscount(order, total);
    saveOrder(order, total);
    sendNotifications(order, total);
}

private void validateOrder(Order order) {
    if (order == null) {
        thrownew IllegalArgumentException("订单不能为空");
    }
    if (order.getItems() == null || order.getItems().isEmpty()) {
        thrownew IllegalArgumentException("订单项不能为空");
    }
    if (order.getCustomer() == null) {
        thrownew IllegalArgumentException("客户信息不能为空");
    }
}

private double calculateOrderTotal(Order order) {
    double total = 0;
    for (OrderItem item : order.getItems()) {
        double price = item.getPrice();
        int quantity = item.getQuantity();
        total += price * quantity;
    }
    return total;
}

private double applyDiscount(Order order, double total) {
    if (order.getCustomer().isVip()) {
        return total * 0.9;
    }
    return total;
}

private void saveOrder(Order order, double total) {
    order.setTotal(total);
    orderRepository.save(order);
}

private void sendNotifications(Order order, double total) {
    String message = "订单" + order.getId() + "已处理,总价:" + total;
    emailService.sendEmail(order.getCustomer().getEmail(), "订单处理通知", message);
    smsService.sendSms(order.getCustomer().getPhone(), message);
}

通过提取方法,我们将一个大方法拆分成了多个小方法,每个方法只负责一个功能。

这样不仅提高了代码的可读性,也使得每个方法更容易测试和维护。

2. 引入解释性变量

有时候,一个复杂的表达式可能难以理解。

这时,我们可以引入一个解释性变量来提高代码的可读性。

重构前:

public boolean isEligibleForDiscount(Customer customer, Order order) {
    return (customer.getAge() >= 60 || (customer.getMembershipYears() > 5 && order.getTotal() > 1000)) 
        && !customer.hasOutstandingPayments();
    
}

重构后:

public boolean isEligibleForDiscount(Customer customer, Order order) {
    boolean isSenior = customer.getAge() >= 60;
    boolean isLoyalCustomerWithLargeOrder = customer.getMembershipYears() > 5 && order.getTotal() > 1000;
    boolean hasNoOutstandingPayments = !customer.hasOutstandingPayments();
    return (isSenior || isLoyalCustomerWithLargeOrder) && hasNoOutstandingPayments;
}

通过引入解释性变量,我们使得复杂的条件表达式更加清晰易懂。每个变量都有一个描述性的名称,使得代码的意图更加明确。

3. 替换条件表达式

有些小伙伴在处理不同类型的对象时,可能会使用大量的条件语句(if-else或switch)。

这样的代码不仅冗长,而且每次添加新类型都需要修改这些条件语句,违反了开闭原则。

重构前:

public class PaymentProcessor {
    public void processPayment(Payment payment) {
        if (payment.getType().equals("CREDIT_CARD")) {
            // 处理信用卡支付
            validateCreditCard(payment);
            chargeCreditCard(payment);
        } else if (payment.getType().equals("PAYPAL")) {
            // 处理PayPal支付
            validatePayPalAccount(payment);
            chargePayPalAccount(payment);
        } else if (payment.getType().equals("BANK_TRANSFER")) {
            // 处理银行转账
            validateBankAccount(payment);
            initiateTransfer(payment);
        } else {
            throw new IllegalArgumentException("不支持的支付类型:" + 
            payment.getType());
        }
    }
    // 其他方法...
}

重构后:

public interface PaymentProcessor {
    void processPayment(Payment payment);
}

public class CreditCardProcessor implements PaymentProcessor {
    @Override
    public void processPayment(Payment payment) {
        validateCreditCard(payment);
        chargeCreditCard(payment);
    }
    
    // 其他方法...
}

public class PayPalProcessor implements PaymentProcessor {
    @Override
    public void processPayment(Payment payment) {
        validatePayPalAccount(payment);
        chargePayPalAccount(payment);
    }
    
    // 其他方法...
}

public class BankTransferProcessor implements PaymentProcessor {
    @Override
    public void processPayment(Payment payment) {
        validateBankAccount(payment);
        initiateTransfer(payment);
    }
    
    // 其他方法...
}

public class PaymentFactory {
    public static PaymentProcessor getProcessor(String paymentType) 
    {
        if (paymentType.equals("CREDIT_CARD")) {
            return new CreditCardProcessor();
        } elseif (paymentType.equals("PAYPAL")) {
            return new PayPalProcessor();
        } elseif (paymentType.equals("BANK_TRANSFER")) {
            return new BankTransferProcessor();
        } else {
            throw new IllegalArgumentException("不支持的支付类型:" + paymentType);
        }
    }
}

// 使用
PaymentProcessor processor = PaymentFactory.getProcessor(payment.getType());
processor.processPayment(payment);

通过使用多态,我们将不同类型的支付处理逻辑分散到各自的类中,使得代码更加模块化,也更容易扩展。

当需要添加新的支付类型时,只需创建一个新的处理器类,而不需要修改现有的代码。

4. 移除重复代码

代码重复是软件开发中的一大问题。

重复的代码不仅增加了代码量,也增加了维护的难度。当需要修改一个功能时,可能需要在多个地方进行相同的修改,这增加了出错的可能性。

重构前:

public class UserService {
    public User findUserById(Long id) {
        // 记录日志
        Logger logger = LoggerFactory.getLogger(UserService.class);
        logger.info("查询用户,ID:" + id);
        
        // 查询用户
        User user = userRepository.findById(id);
        if (user == null) {
            logger.error("用户不存在,ID:" + id);
            thrownew UserNotFoundException("用户不存在,ID:" + id);
        }
        
        return user;
    }
    
    public User findUserByEmail(String email) {
        // 记录日志
        Logger logger = LoggerFactory.getLogger(UserService.class);
        logger.info("查询用户,Email:" + email);
        
        // 查询用户
        User user = userRepository.findByEmail(email);
        if (user == null) {
            logger.error("用户不存在,Email:" + email);
            throw new UserNotFoundException("用户不存在,Email:" + email);
        }
        return user;
    }
}

重构后:

public class UserService {
    private static final Logger logger = LoggerFactory.getLogger(UserService.class);
  
    public User findUserById(Long id) {
        logger.info("查询用户,ID:" + id);
        return findUserOrThrow(() -> userRepository.findById(id), "用户不存在,ID:" + id); 
    }
    
    public User findUserByEmail(String email) {
        logger.info("查询用户,Email:" + email);
        return findUserOrThrow(() -> userRepository.findByEmail(email), "用户不存在,Email:" + email);
    }
    
    private User findUserOrThrow(Supplier<User> finder, String errorMessage) {
        User user = finder.get();
        if (user == null) {
            logger.error(errorMessage);
            throw new UserNotFoundException(errorMessage);
        }
        return user;
    }
}

通过提取公共方法,我们消除了重复代码,使得代码更加简洁。

当需要修改查询用户的逻辑时,只需要修改一个地方,而不是多个地方。

5. 引入参数对象

当一个方法有多个参数时,特别是当这些参数经常一起出现时,可以考虑将它们封装成一个对象。

重构前:

public class ReportGenerator {
    public Report generateReport(String startDate, String endDate, 
    String department, String format, boolean includeCharts) {
        // 生成报告的逻辑
        // ...
    }
    
    public void emailReport(String startDate, String endDate, 
    String department, String format, boolean includeCharts, String email) {
        Report report = generateReport(startDate, endDate, 
        department, format, includeCharts);
        // 发送报告的逻辑
        // ...
    }
    
    public void saveReport(String startDate, String endDate, String department, String format, boolean includeCharts, String filePath) {
        Report report = generateReport(startDate, endDate, 
        department, format, includeCharts);
        // 保存报告的逻辑
        // ...
    }
}

重构后:

public class ReportCriteria {
    private String startDate;
    private String endDate;
    private String department;
    private String format;
    private boolean includeCharts;
    
    // 构造函数、getter和setter
    // ...
}

public class ReportGenerator {
    public Report generateReport(ReportCriteria criteria) {
        // 生成报告的逻辑
        // ...
    }
    
    public void emailReport(ReportCriteria criteria, String email) {
        Report report = generateReport(criteria);
        // 发送报告的逻辑
        // ...
    }
    
    public void saveReport(ReportCriteria criteria, String filePath) {
        Report report = generateReport(criteria);
        // 保存报告的逻辑
        // ...
    }
}

通过引入参数对象,我们减少了方法的参数数量,使得方法调用更加简洁。同时,参数对象也可以包含与这些参数相关的行为,进一步提高代码的内聚性。

6. 使用策略模式

有些小伙伴在处理不同的算法或策略时,可能会使用大量的条件语句。

这样的代码不仅难以维护,也难以扩展。

重构前:

public class ShippingCalculator {
    public double calculateShippingCost(Order order, String shippingMethod) {
        if (shippingMethod.equals("STANDARD")) {
            // 标准运费计算逻辑
            return order.getWeight() * 0.5;
        } else if (shippingMethod.equals("EXPRESS")) {
            // 快递运费计算逻辑
            return order.getWeight() * 1.0 + 10;
        } else if (shippingMethod.equals("OVERNIGHT")) {
            // 隔夜运费计算逻辑
            return order.getWeight() * 1.5 + 20;
        } else {
            throw new IllegalArgumentException("不支持的运输方式:" + shippingMethod);
        }
    }
}

重构后:

public interface ShippingStrategy {
    double calculateShippingCost(Order order);
}

public class StandardShipping implements ShippingStrategy {
    @Override
    public double calculateShippingCost(Order order) {
        return order.getWeight() * 0.5;
    }
}

public class ExpressShipping implements ShippingStrategy {
    @Override
    public double calculateShippingCost(Order order) {
        return order.getWeight() * 1.0 + 10;
    }
}

public class OvernightShipping implements ShippingStrategy {
    @Override
    public double calculateShippingCost(Order order) {
        return order.getWeight() * 1.5 + 20;
    }
}

public class ShippingCalculator {
    private Map<String, ShippingStrategy> strategies = new HashMap<>
    ();
    
    public ShippingCalculator() {
        strategies.put("STANDARD", new StandardShipping());
        strategies.put("EXPRESS", new ExpressShipping());
        strategies.put("OVERNIGHT", new OvernightShipping());
    }
    
    public double calculateShippingCost(Order order, String shippingMethod) {
        ShippingStrategy strategy = strategies.get(shippingMethod);
        if (strategy == null) {
            throw new IllegalArgumentException("不支持的运输方式:" + shippingMethod);
        }
        return strategy.calculateShippingCost(order);
    }
}

通过使用策略模式,我们将不同的运费计算逻辑分散到各自的类中,使得代码更加模块化,也更容易扩展。

当需要添加新的运输方式时,只需创建一个新的策略类,并将其添加到策略映射中,而不需要修改现有的代码。

7. 使用构建者模式

当一个类有多个构造参数时,特别是当有些参数是可选的时,可以考虑使用构建者模式。

重构前:

public class User {
    private String username;
    private String email;
    private String firstName;
    private String lastName;
    private String phone;
    private String address;
    private String city;
    private String country;
    private String postalCode;
    
    // 构造函数
    public User(String username, String email) {
        this.username = username;
        this.email = email;
    }
    
    public User(String username, String email, String firstName, String lastName) {
        this.username = username;
        this.email = email;
        this.firstName = firstName;
        this.lastName = lastName;
    }
    
    public User(String username, String email, String firstName, String lastName, String phone) {
        this.username = username;
        this.email = email;
        this.firstName = firstName;
        this.lastName = lastName;
        this.phone = phone;
    }
    
    // 更多构造函数...
    
    // getter和setter
    // ...
}

重构后:

public class User {
    private String username;
    private String email;
    private String firstName;
    private String lastName;
    private String phone;
    private String address;
    private String city;
    private String country;
    private String postalCode;
    
    private User(Builder builder) {
        this.username = builder.username;
        this.email = builder.email;
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.phone = builder.phone;
        this.address = builder.address;
        this.city = builder.city;
        this.country = builder.country;
        this.postalCode = builder.postalCode;
    }
    
    // getter(没有setter,使对象不可变)
    // ...
    
    public static class Builder {
        // 必需参数
        private final String username;
        private final String email;
        
        // 可选参数
        private String firstName;
        private String lastName;
        private String phone;
        private String address;
        private String city;
        private String country;
        private String postalCode;
        
        public Builder(String username, String email) {
            this.username = username;
            this.email = email;
        }
        
        public Builder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        } 
        
        public Builder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }
         
        public Builder phone(String phone) {
            this.phone = phone;
            return this;
        }
        
        public Builder address(String address) {
            this.address = address;
            return this;
        }
        
        public Builder city(String city) {
            this.city = city;
            returnthis;
        }
        
        public Builder country(String country) {
            this.c ountry = country;
            return this;
        }
        
        public Builder postalCode(String postalCode) {
            this.postalCode = postalCode;
            return this;
        }
        
        public User build() {
            return new User(this);
        }
    }
}

// 使用
User user = new User.Builder("johndoe", "john.doe@example.com")
    .firstName("John")
    .lastName("Doe")
    .phone("1234567890")
    .build();

通过使用构建者模式,我们解决了构造函数参数过多的问题,使得对象创建更加灵活和可读。

同时,构建者模式也可以确保对象在创建后是不可变的,提高了代码的安全性。

8. 使用工厂方法

当对象的创建逻辑比较复杂时,可以考虑使用工厂方法。

重构前:

public class ProductService {
    public Product createProduct(String type, String name, double price) {
        Product product;
        if (type.equals("PHYSICAL")) {
            product = new PhysicalProduct(name, price);
            // 设置物理产品的属性
            // ...
        } else if (type.equals("DIGITAL")) {
            product = new DigitalProduct(name, price);
            // 设置数字产品的属性
            // ...
        } else if (type.equals("SUBSCRIPTION")) {
            product = new SubscriptionProduct(name, price);
            // 设置订阅产品的属性
            // ...
        } else {
            throw new IllegalArgumentException("不支持的产品类型:" + type);
        }
        return product;
    }
}

重构后:

public abstract class ProductFactory {
    public static Product createProduct(String type, String name, 
    double price) {
        if (type.equals("PHYSICAL")) {
            return createPhysicalProduct(name, price);
        } else if (type.equals("DIGITAL")) {
            return createDigitalProduct(name, price);
        } else if (type.equals("SUBSCRIPTION")) {
            return createSubscriptionProduct(name, price);
        } else {
            throw new IllegalArgumentException("不支持的产品类型:" + type);
        }
    }
    
    private static Product createPhysicalProduct(String name, double price) {
        PhysicalProduct product = new PhysicalProduct(name, price);
        // 设置物理产品的属性
        // ...
        return product;
    }
    
    private static Product createDigitalProduct(String name, double price) {
        DigitalProduct product = new DigitalProduct(name, price);
        // 设置数字产品的属性
        // ...
        return product;
    }
    
    private static Product createSubscriptionProduct(String name, double price) {
        SubscriptionProduct product = new SubscriptionProduct(name, price);
        // 设置订阅产品的属性
        // ...
        return product;
    }
}

// 使用
Product product = ProductFactory.createProduct("PHYSICAL", "书籍", 29.99);

通过使用工厂方法,我们将对象的创建逻辑从客户端代码中分离出来,使得代码更加模块化,也更容易维护。

当需要添加新的产品类型时,只需在工厂类中添加相应的创建方法,而不需要修改客户端代码。

9. 使用Optional避免空指针异常

空指针异常(NullPointerException)是Java中最常见的异常之一。

为了避免这种异常,我们可以使用Java 8引入的Optional类。

重构前:

public class UserService {
    public User findUserById(Long id) {
        // 查询用户
        return userRepository.findById(id);
    }
    
    public String getUserEmail(Long id) {
        User user = findUserById(id);
        if (user != null) {
            String email = user.getEmail();
            if (email != null) {
                return email;
            }
        }
        return"未知";
    }
}

重构后:

public class UserService {
    public Optional<User> findUserById(Long id) {
        // 查询用户
        User user = userRepository.findById(id);
        return Optional.ofNullable(user);
    }
    
    public String getUserEmail(Long id) {
        return findUserById(id)
            .map(User::getEmail)
            .orElse("未知");
    }
}

通过使用Optional,我们明确表示方法可能返回空值,使得代码更加清晰。

同时,Optional提供了丰富的API,如map、filter、orElse等,使得处理可能为空的值更加方便。

10. 使用Stream API简化集合操作

Java 8引入的Stream API提供了一种函数式编程的方式来处理集合,使得代码更加简洁和可读。

重构前:

public class OrderService {
    public List<Order> findLargeOrders(List<Order> orders) {
        List<Order> largeOrders = new ArrayList<>();
        for (Order order : orders) {
            if (order.getTotal() > 1000) {
                largeOrders.add(order);
            }
        }
        return largeOrders;
    }
    
    public double calculateTotalRevenue(List<Order> orders) {
        double total = 0;
        for (Order order : orders) {
            total += order.getTotal();
        }
        return total;
    }
    
    public List<String> getCustomerNames(List<Order> orders) {
        List<String> names = new ArrayList<>();
        for (Order order : orders) {
            String name = order.getCustomer().getName();
            if (!names.contains(name)) {
                names.add(name);
            }
        }
        return names;
    }
}

重构后:

public class OrderService {
    public List<Order> findLargeOrders(List<Order> orders) {
        return orders.stream()
            .filter(order -> order.getTotal() > 1000)
            .collect(Collectors.toList());
    }
    
    public double calculateTotalRevenue(List<Order> orders) {
        return orders.stream()
            .mapToDouble(Order::getTotal)
            .sum();
    }
    
    public List<String> getCustomerNames(List<Order> orders) {
        return orders.stream()
            .map(order -> order.getCustomer().getName())
            .distinct()
            .collect(Collectors.toList());
    }
}

通过使用Stream API,我们将命令式的代码转换为声明式的代码,使得代码更加简洁和可读。

Stream API提供了丰富的操作,如filter、map、reduce等,使得处理集合更加方便。

11. 使用Lambda表达式简化匿名内部类

Java 8引入的Lambda表达式提供了一种更简洁的方式来创建匿名函数,特别适合用于替代匿名内部类。

重构前:

public class ButtonHandler {
    public void setupButton(Button button) {
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                // 处理点击事件
                System.out.println("按钮被点击");
            }
        });
    }
    
    public void sortUsers(List<User> users) {
        Collections.sort(users, new Comparator<User>() {
            @Override
            public int compare(User u1, User u2) {
                return u1.getName().compareTo(u2.getName());
            }
        });
    }
}

重构后:

public class ButtonHandler {
    public void setupButton(Button button) {
        button.setOnClickListener(view -> {
            // 处理点击事件
            System.out.println("按钮被点击");
        });
    }
    
    public void sortUsers(List<User> users) {
        Collections.sort(users, (u1, u2) -> u1.getName().compareTo(u2.getName()));
        // 或者更简洁地
        users.sort(Comparator.comparing(User::getName));
    }
}

通过使用Lambda表达式,我们将冗长的匿名内部类替换为简洁的函数式表达式,使得代码更加简洁和可读。

12. 使用方法引用简化Lambda表达式

Java 8引入的方法引用提供了一种更简洁的方式来引用已有的方法,特别适合用于替代简单的Lambda表达式。

重构前:

public class UserProcessor {
    public List<String> getUserNames(List<User> users) {
        return users.stream()
            .map(user -> user.getName())
            .collect(Collectors.toList());
    }
    
    public void printUsers(List<User> users) {
        users.forEach(user -> System.out.println(user));
    }
    
    public List<User> createUsers(List<String> names) {
        return names.stream()
            .map(name -> new User(name))
            .collect(Collectors.toList());
    }
}

重构后:

public class UserProcessor {
    public List<String> getUserNames(List<User> users) {
        return users.stream()
            .map(User::getName)
            .collect(Collectors.toList());
    }
    
    public void printUsers(List<User> users) {
        users.forEach(System.out::println);
    }
    
    public List<User> createUsers(List<String> names) {
        return names.stream()
            .map(User::new)
            .collect(Collectors.toList());
    }
}

通过使用方法引用,我们将简单的Lambda表达式替换为更简洁的方法引用,使得代码更加简洁和可读。

13. 使用CompletableFuture简化异步编程

Java 8引入的CompletableFuture提供了一种更简洁的方式来处理异步操作,特别适合用于替代传统的回调方式。

重构前:

public class UserService {
    public void processUser(Long userId, Callback<User> callback) {
        // 异步查询用户
        userRepository.findByIdAsync(userId, new Callback<User>() {
            @Override
            public void onSuccess(User user) {
                // 异步查询用户的订单
                orderRepository.findByUserIdAsync(userId, new
                Callback<List<Order>>() {
                    @Override
                    public void onSuccess(List<Order> orders) {
                        // 处理用户和订单
                        user.setOrders(orders);
                        callback.onSuccess(user);
                    }
                    
                    @Override
                    public void onError(Exception e) {
                        callback.onError(e);
                    }
                });
            }
            
            @Override
            public void onError(Exception e) {
                callback.onError(e);
            }
        });
    }
}

重构后:

public class UserService {
    public CompletableFuture<User> processUser(Long userId) {
        return userRepository.findByIdAsync(userId)
            .thenCompose(user -> orderRepository.findByUserIdAsync(userId)
            .thenApply(orders -> {
                    user.setOrders(orders);
                    return user;
            }));
    }
}

// 使用
userService.processUser(123L)
    .thenAccept(user -> {
        // 处理用户
        System.out.println("用户:" + user.getName());
        System.out.println("订单数:" + user.getOrders().size());
    })
    .exceptionally(e -> {
        // 处理异常
        System.err.println("处理用户时出错:" + e.getMessage());
        returnnull;
    });

通过使用CompletableFuture,我们将嵌套的回调转换为链式的调用,使得代码更加简洁和可读。

CompletableFuture提供了丰富的API,如thenApply、thenCompose、thenAccept等,使得处理异步操作更加方便。

14. 使用接口默认方法简化接口实现

Java 8引入的接口默认方法允许在接口中提供方法的默认实现,使得接口的演化更加灵活。

重构前:

public interface PaymentProcessor {
    void processPayment(Payment payment);
    void refundPayment(Payment payment);
    void cancelPayment(Payment payment);
}

public class CreditCardProcessor implements PaymentProcessor {
    @Override
    public void processPayment(Payment payment) {
        // 处理信用卡支付
    }
    
    @Override
    public void refundPayment(Payment payment) {
        // 处理信用卡退款
    }
    
    @Override
    public void cancelPayment(Payment payment) {
        // 取消支付并退款
        refundPayment(payment);
    }
}

public class PayPalProcessor implements PaymentProcessor {
    @Override
    public void processPayment(Payment payment) {
        // 处理PayPal支付
    }
    
    @Override
    public void refundPayment(Payment payment) {
        // 处理PayPal退款
    }
    
    @Override
    public void cancelPayment(Payment payment) {
        // 取消支付并退款
        refundPayment(payment);
    }
}

重构后:

public interface PaymentProcessor {
    void processPayment(Payment payment);
    void refundPayment(Payment payment);
    
    default void cancelPayment(Payment payment) {
        // 默认实现:取消支付并退款
        refundPayment(payment);
    }
}

public class CreditCardProcessor implements PaymentProcessor {
    @Override
    public void processPayment(Payment payment) {
        // 处理信用卡支付
    }
    
    @Override
    public void refundPayment(Payment payment) {
        // 处理信用卡退款
    }
}

public class PayPalProcessor implements PaymentProcessor {
    @Override
    public void processPayment(Payment payment) {
        // 处理PayPal支付
    }
    
    @Override
    public void refundPayment(Payment payment) {
        // 处理PayPal退款
    }
}

通过使用接口默认方法,我们将公共的实现从具体的类中提取到接口中,减少了重复代码。

当需要修改公共实现时,只需修改接口中的默认方法,而不需要修改所有实现类。

15. 使用枚举替代常量

使用枚举可以提供类型安全的常量,避免使用魔法数字或字符串常量。

重构前:

public class OrderStatus {
    public static final String PENDING = "PENDING";
    public static final String PROCESSING = "PROCESSING";
    public static final String SHIPPED = "SHIPPED";
    public static final String DELIVERED = "DELIVERED";
    public static final String CANCELLED = "CANCELLED";
}

public class Order {
    private String status;
    
    public void setStatus(String status) {
        this.status = status;
    }
    
    public String getStatus() {
        return status;
    }
    
    public boolean isCancellable() {
        return status.equals(OrderStatus.PENDING) || status.equals(OrderStatus.PROCESSING);
    }
}

// 使用
Order order = new Order();
order.setStatus(OrderStatus.PENDING);
// 可能的错误:使用了未定义的常量
order.setStatus("REFUNDED");

重构后:

public enum OrderStatus {
    PENDING,
    PROCESSING,
    SHIPPED,
    DELIVERED,
    CANCELLED;
    
    public boolean isCancellable() {
        return this == PENDING || this == PROCESSING;
    }
}

public class Order {
    private OrderStatus status;
    
    public void setStatus(OrderStatus status) {
        this.status = status;
    }
    
    public OrderStatus getStatus() {
        return status;
    }
    
    public boolean isCancellable() {
        return status.isCancellable();
    }
}

// 使用
Order order = new Order();
order.setStatus(OrderStatus.PENDING);
// 编译错误:无法使用未定义的枚举常量
// order.setStatus("REFUNDED");

通过使用枚举,我们提供了类型安全的常量,避免了使用魔法数字或字符串常量可能导致的错误。

同时,枚举也可以包含方法,使得与常量相关的行为更加内聚。

总结

在这篇文章中,我们探讨了15个代码重构的小技巧,从简单的提取方法到高级的设计模式应用。

这些技巧可以帮助我们写出更加简洁、可读、可维护的代码。

代码重构是一个持续的过程,我们应该在日常开发中不断地应用这些技巧,逐步改进我们的代码质量。

记住,好的代码不仅仅是能够正确运行,还应该易于理解、易于修改和易于扩展。

希望这些技巧对你有所帮助,让我们一起写出更好的代码!


文章作者: 威@猫
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 威@猫 !
评论
  目录