文章目录
概述
在软件开发过程中,随着项目规模的增长,代码中可能会出现一些不良的编程习惯,这些习惯被称为“代码的坏味道”。识别并消除这些坏味道是重构过程的重要组成部分。本文档将详细介绍几种常见的代码坏味道,并提供具体的重构建议。
1. 重复代码 (Duplicate Code)
描述: 当相同的代码片段出现在多个地方时,这通常意味着代码需要被提取成单独的方法或模块。
例子:
public class ShoppingCart {
public void calculateTotalPrice(List<Item> items) {
double total = 0;
for (Item item : items) {
total += item.getPrice();
}
System.out.println("Total price: " + total);
}
public void calculateShippingCost(List<Item> items, double shippingRate) {
double totalWeight = 0;
for (Item item : items) {
totalWeight += item.getWeight();
}
double shippingCost = totalWeight * shippingRate;
System.out.println("Shipping cost: " + shippingCost);
}
}
重构建议:
public class ShoppingCart {
private double sumOfItems(List<Item> items, Function<Item, Double> sumFunction) {
double total = 0;
for (Item item : items) {
total += sumFunction.apply(item);
}
return total;
}
public void calculateTotalPrice(List<Item> items) {
double total = sumOfItems(items, Item::getPrice);
System.out.println("Total price: " + total);
}
public void calculateShippingCost(List<Item> items, double shippingRate) {
double totalWeight = sumOfItems(items, Item::getWeight);
double shippingCost = totalWeight * shippingRate;
System.out.println("Shipping cost: " + shippingCost);
}
}
2. 冗长的方法 (Long Method)
描述: 如果一个方法执行了太多的操作或者代码过长,这可能意味着它应该被分解成更小的部分。
例子:
public class ReportGenerator {
public void generateReport(Employee employee) {
System.out.println("Employee Report:");
System.out.println("----------------");
System.out.println("Name: " + employee.getName());
System.out.println("ID: " + employee.getId());
System.out.println("Department: " + employee.getDepartment());
System.out.println("Position: " + employee.getPosition());
System.out.println("Salary: " + employee.getSalary());
System.out.println("Email: " + employee.getEmail());
System.out.println("Phone: " + employee.getPhoneNumber());
System.out.println("Address: " + employee.getAddress());
System.out.println("Joining Date: " + employee.getJoiningDate());
}
}
重构建议:
public class ReportGenerator {
public void generateReport(Employee employee) {
printEmployeeDetails(employee);
}
private void printEmployeeDetails(Employee employee) {
System.out.println("Employee Report:");
System.out.println("----------------");
printLine("Name", employee.getName());
printLine("ID", employee.getId());
printLine("Department", employee.getDepartment());
printLine("Position", employee.getPosition());
printLine("Salary", employee.getSalary());
printLine("Email", employee.getEmail());
printLine("Phone", employee.getPhoneNumber());
printLine("Address", employee.getAddress());
printLine("Joining Date", employee.getJoiningDate());
}
private void printLine(String label, String value) {
System.out.println(label + ": " + value);
}
private void printLine(String label, int value) {
System.out.println(label + ": " + value);
}
private void printLine(String label, double value) {
System.out.println(label + ": " + value);
}
private void printLine(String label, Date value) {
System.out.println(label + ": " + value);
}
}
3. 过多的参数 (Too Many Arguments)
描述: 如果一个方法接收了过多的参数,这可能意味着参数列表需要被精简或替换为一个更复杂的对象。
例子:
public class OrderProcessor {
public void processOrder(String orderId, String customerName, String product, int quantity, double price, String address, String paymentMethod) {
// 处理订单逻辑
}
}
重构建议:
public class OrderProcessor {
public void processOrder(Order order) {
// 处理订单逻辑
}
}
public class Order {
private final String orderId;
private final Customer customer;
private final Product product;
public Order(String orderId, Customer customer, Product product) {
this.orderId = orderId;
this.customer = customer;
this.product = product;
}
// Getters and other methods...
public String getOrderId() {
return orderId;
}
public Customer getCustomer() {
return customer;
}
public Product getProduct() {
return product;
}
}
public class Customer {
private final String name;
private final Address address;
private final String paymentMethod;
public Customer(String name, Address address, String paymentMethod) {
this.name = name;
this.address = address;
this.paymentMethod = paymentMethod;
}
// Getters and other methods...
public String getName() {
return name;
}
public Address getAddress() {
return address;
}
public String getPaymentMethod() {
return paymentMethod;
}
}
public class Product {
private final String productName;
private final int quantity;
private final double price;
public Product(String productName, int quantity, double price) {
this.productName = productName;
this.quantity = quantity;
this.price = price;
}
// Getters and other methods...
public String getProductName() {
return productName;
}
public int getQuantity() {
return quantity;
}
public double getPrice() {
return price;
}
}
public class Address {
private final String street;
private final String city;
private final String zipCode;
public Address(String street, String city, String zipCode) {
this.street = street;
this.city = city;
this.zipCode = zipCode;
}
// Getters and other methods...
public String getStreet() {
return street;
}
public String getCity() {
return city;
}
public String getZipCode() {
return zipCode;
}
}
4. 散乱的变动 (Scattered Changes)
描述: 当相关的变更分散在多个地方时,这表明代码需要更好的组织。
例子:
public class UserManagement {
public void updateUser(User user) {
// 更新用户信息
user.setName("New Name");
user.setEmail("new.email@example.com");
// 更改密码
user.setPassword("newPassword123");
}
public void resetUser(User user) {
// 重置用户信息
user.setName("Default Name");
user.setEmail("default.email@example.com");
// 更改密码
user.setPassword("defaultPassword123");
}
}
重构建议:
public class UserManagement {
public void updateUser(User user, String name, String email, String password) {
user.setName(name);
user.setEmail(email);
user.setPassword(password);
}
public void resetUser(User user) {
updateUser(user, "Default Name", "default.email@example.com", "defaultPassword123");
}
}
5. 冗余注释 (Redundant Comments)
描述: 当注释重复了代码本身的功能说明时,这样的注释是没有必要的。
例子:
public class Calculator {
/**
* This method adds two numbers.
* @param a the first number
* @param b the second number
* @return the sum of a and b
*/
public int add(int a, int b) {
// Add the two numbers
return a + b;
}
}
重构建议:
public class Calculator {
/**
* Adds two numbers.
*
* @param a the first number
* @param b the second number
* @return the sum of a and b
*/
public int add(int a, int b) {
return a + b;
}
}
6. 复杂的条件语句 (Complex Conditional Logic)
描述: 如果条件语句过于复杂,这可能意味着需要简化逻辑。
例子:
public class DiscountCalculator {
public double applyDiscount(Order order) {
double discount = 0;
if (order.getTotalAmount() > 100 && order.getTotalAmount() <= 200) {
discount = 10; // 10% off
} else if (order.getTotalAmount() > 200 && order.getTotalAmount() <= 500) {
discount = 20; // 20% off
} else if (order.getTotalAmount() > 500) {
discount = 30; // 30% off
}
return order.getTotalAmount() - (order.getTotalAmount() * (discount / 100));
}
}
重构建议:
public class DiscountCalculator {
private static final Map<Integer, Integer> DISCOUNTS = Map.of(
100, 10,
200, 20,
500, 30
);
public double applyDiscount(Order order) {
double discount = 0;
int totalAmount = order.getTotalAmount();
DISCOUNTS.forEach((threshold, rate) -> {
if (totalAmount > threshold) {
discount = rate;
}
});
return order.getTotalAmount() - (order.getTotalAmount() * (discount / 100.0));
}
}
7. 过大的类 (Large Class)
描述: 如果一个类承担了过多的责任,这通常意味着类需要被分割成更小的、职责更单一的类。
例子:
public class EmployeeManager {
public void createEmployee(String name, String email, String department) {
// 创建员工
}
public void updateEmployee(Employee employee, String newName, String newEmail, String newDepartment) {
// 更新员工信息
}
public void deleteEmployee(Employee employee) {
// 删除员工
}
public void listEmployees() {
// 列出所有员工
}
public void sendEmail(Employee employee, String subject, String message) {
// 发送邮件给员工
}
}
重构建议:
public class EmployeeManager {
private final EmployeeRepository repository;
private final EmailService emailService;
public EmployeeManager(EmployeeRepository repository, EmailService emailService) {
this.repository = repository;
this.emailService = emailService;
}
public void createEmployee(String name, String email, String department) {
// 创建员工
Employee employee = new Employee(name, email, department);
repository.save(employee);
}
public void updateEmployee(Employee employee, String newName, String newEmail, String newDepartment) {
// 更新员工信息
employee.setName(newName);
employee.setEmail(newEmail);
employee.setDepartment(newDepartment);
repository.update(employee);
}
public void deleteEmployee(Employee employee) {
// 删除员工
repository.delete(employee);
}
public List<Employee> listEmployees() {
// 列出所有员工
return repository.findAll();
}
public void sendEmail(Employee employee, String subject, String message) {
// 发送邮件给员工
emailService.sendEmail(employee.getEmail(), subject, message);
}
}
public interface EmployeeRepository {
void save(Employee employee);
void update(Employee employee);
void delete(Employee employee);
List<Employee> findAll();
}
public interface EmailService {
void sendEmail(String to, String subject, String message);
}
结论
通过识别和消除代码中的“坏味道”,我们可以显著提高代码的质量、可读性和可维护性。重构是软件开发过程中不可或缺的一部分,它有助于确保代码随着时间的推移仍然易于理解和修改。上述示例提供了一些基本的指导原则,但在实际应用中可能还需要根据具体情况做出适当的调整。