Fundamentals 19 min read

25 Common Code Smells and Their Refactoring Solutions

This article explains twenty‑five typical code smells—such as duplicated code, long methods, large classes, and excessive parameters—and provides concrete refactoring techniques like Extract Method, Extract Class, and Move Method to improve readability, maintainability, and design quality in object‑oriented software.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
25 Common Code Smells and Their Refactoring Solutions

1. Duplicated Code

Duplicated code appears in different locations with identical structure, making maintenance difficult because changes must be applied in multiple places.

Three typical scenarios and their optimizations:

Two methods in the same class share the same statements – use Extract Method to create a common method.

Two sibling subclasses contain the same code – extract the common method to the parent class.

Unrelated classes duplicate code – extract the duplicated logic into a new utility class ( Extract Class ).

class A {
    public void method1() {
        doSomething1
        doSomething2
        doSomething3
    }
    public void method2() {
        doSomething1
        doSomething2
        doSomething4
    }
}
class A {
    public void method1() {
        commonMethod();
        doSomething3
    }
    public void method2() {
        commonMethod();
        doSomething4
    }
    public void commonMethod() {
        doSomething1
        doSomething2
    }
}

2. Long Method

Methods that span hundreds of lines are hard to read and understand. The solution is to apply Extract Method to break the method into smaller, well‑named functions.

public class Test {
    public void printOwing() {
        // print banner
        System.out.println("****************");
        // calculate totalAmount
        double totalAmount = 0.0;
        // print details
        System.out.println("name:" + name);
        System.out.println("amount:" + totalAmount);
    }
}
public class Test {
    public void printOwing() {
        printBanner();
        double totalAmount = getTotalAmount();
        printDetail(totalAmount);
    }
    void printBanner() { ... }
    double getTotalAmount() { ... }
    void printDetail(double totalAmount) { ... }
}

3. Large Class

A class that does too many unrelated things reduces readability and performance. Apply Extract Class to separate responsibilities.

class A {
    void printOrder() { System.out.println("订单"); }
    void printGoods() { System.out.println("商品"); }
    void printPoints() { System.out.println("积分"); }
}
class Order { void printOrder() { ... } }
class Goods { void printGoods() { ... } }
class Points { void printPoints() { ... } }

4. Long Parameter List

Methods with many parameters are hard to use and evolve. Group related parameters into a DTO.

public void getUserInfo(String name, String age, String sex, String mobile) { ... }
public void getUserInfo(UserInfoParamDTO dto) { ... }
class UserInfoParamDTO { String name; String age; String sex; String mobile; }

5. Divergent Change

When a single class requires multiple unrelated modifications, split the class so that related changes stay together. Example: extract an IEngine interface and move brand‑specific logic to subclasses.

public interface IEngine { void start(); }
class HybridEngineImpl implements IEngine { public void start() { ... } }

6. Shotgun Surgery

Scattered small changes across many classes can be consolidated by moving fields or methods into a single class.

public class DbUtils { @Value("${db.mysql.url}") private String mysqlDbUrl; }

7. Feature Envy

A method that heavily uses another class's data should be moved to that class.

class User { void getFullPhoneNumber(Phone phone) { ... } }

8. Data Clumps

When several data items always appear together, encapsulate them into a value object.

class User { private String firstName; private String lastName; private String province; private String city; ... }
class User { private UserName username; private Address address; }
class UserName { private String firstName; private String lastName; }
class Address { private String province; private String city; private String area; private String street; }

9. Primitive Obsession

Wrap frequently co‑occurring primitive fields into domain objects.

class Order { private String customName; private String address; private Integer orderId; private Integer price; }
class Order { private Custom custom; private Integer orderId; private Integer price; }
class Custom { private String name; private String address; }

10. Switch Statements

Replace long if…else or switch chains with polymorphism.

interface IMedalService { void showMedal(); }
class GuardMedalServiceImpl implements IMedalService { public void showMedal() { System.out.println("展示守护勋章"); } }

11. Parallel Inheritance Hierarchies

When two class hierarchies evolve together, consider removing one inheritance relationship or using composition.

12. Lazy Class

Merge the functionality of a rarely used class into a more relevant class and delete the lazy class.

13. Speculative Generality

Avoid over‑engineering; remove unused abstractions, parameters, or hierarchies.

14. Temporary Field

Eliminate fields that exist only for a short‑lived calculation; compute the value locally instead.

15. Message Chains

Break long chains of calls by introducing delegation methods or moving logic closer to the client.

16. Middle Man

Remove unnecessary forwarding methods; let clients interact directly with the real service.

17. Inappropriate Intimacy

Reduce tight coupling between classes by extracting shared behavior into a common component.

18. Alternative Classes with Different Interfaces

Unify similar functionality by renaming, moving methods, or introducing an abstract superclass.

19. Incomplete Library Class

Wrap or extend third‑party classes when they lack needed features.

20. Data Class

Encapsulate data and related behavior; avoid exposing public fields.

21. Refused Bequest

When a subclass uses only a few inherited members, replace inheritance with delegation or push down unused members.

22. Comments

Prefer self‑describing code over excessive comments; use comments only for complex business rules.

23. Bad Naming

Choose clear, expressive names for variables, methods, and classes.

24. Magic Numbers

Replace unexplained literals with named constants or enums.

25. Chaotic Layer Calls

Maintain proper layering (controller → service → DAO); avoid direct DAO calls from controllers.

References and acknowledgments are listed at the end of the original article.

software designrefactoringclean-codeobject-orientedCode Smell
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.