# Refactoring 022 - Extract Common Ancestor

*Make your class hierarchy clear and flexible*

> TL;DR: Extract a common abstract class to mimic real-world structure.

# Problems Addressed

- [Duplicate Code](https://maximilianocontieri.com/refactoring-013-remove-repeated-code)
- Inappropriate Inheritance
- [Shotgun Surgery](https://maximilianocontieri.com/code-smell-66-shotgun-surgery)
- Big Class
- [Feature Envy](https://maximilianocontieri.com/code-smell-63-feature-envy)
- High Coupling
- [Concrete classes subclassified](https://maximilianocontieri.com/code-smell-43-concrete-classes-subclassified)
- Parent class [not abstract](https://maximilianocontieri.com/code-smell-161-abstractfinalundefined-classes)

# Related Code Smells

%[https://maximilianocontieri.com/code-smell-66-shotgun-surgery]

%[https://maximilianocontieri.com/code-smell-255-parallel-hierarchies]

%[https://maximilianocontieri.com/code-smell-63-feature-envy]

%[https://maximilianocontieri.com/code-smell-43-concrete-classes-subclassified]

%[https://maximilianocontieri.com/code-smell-161-abstractfinalundefined-classes]

# Steps

1. Identify common behaviors in both classes
2. Create an abstract class with shared behavior and no implementation
3. Move common logic to the abstract class
4. Update subclasses to inherit from the abstract class

# Sample Code

## Before

<!-- [Gist Url](https://gist.github.com/mcsee/5de0a92aa03e0374fdafd6be1132b121) -->

```java
class Car {
    void drive() {
        System.out.println("Driving a car");
    }
}

class Truck extends Car {
    void load() {
        System.out.println("Loading cargo");
    }

    void unload() {
        System.out.println("Unloading cargo");
    }
}

// Truck reuses driving method
// Overriding it would be another code smell
// Violating Liskov Substitution rule
```

## After

<!-- [Gist Url](https://gist.github.com/mcsee/8b35009d835f7646ce56080a93d9839a) -->

```java
abstract class Vehicle {
    // 2. Create an abstract class
    // with shared behavior and no implementation
    abstract void drive();
    // 1. Identify common behaviors in both classes
    // 3. Move common logic to the abstract class
}

class Car extends Vehicle {
    // 4. Update subclasses to inherit from the abstract class
    void drive() {
        System.out.println("Driving a car");
    }
}

class Truck extends Vehicle {
    // 4. Update subclasses to inherit from the abstract class
    void drive() {
        System.out.println("Driving a truck");
        // Implementation is different than the car's
    }

    void load() {
        System.out.println("Loading cargo");
    }

    void unload() {
        System.out.println("Unloading cargo");
    }
}
```

# Type

[X] Semi-Automatic

# Safety

This refactoring is safe if you identify all common behaviors correctly and move one method at a time running the tests.

# Why is the Code Better?

It reduces duplication, simplifies maintenance, and makes it easier to extend functionality by adding new concrete realizations.

# How Does it Improve the Bijection?

By introducing an abstract class, the code better reflects the [real-world](https://maximilianocontieri.com/the-one-and-only-software-design-principle) hierarchy, creating a clear relationship between the generic and specific types.

# Refactor with AI

| Without Proper Instructions    | With Specific Instructions |
| -------- | ------- |
| [ChatGPT](https://chat.openai.com/?q=Correct+and+explain+this+code%3A+%60%60%60java%0D%0Aclass+Car+%7B%0D%0A++++void+drive%28%29+%7B%0D%0A++++++++System.out.println%28%22Driving+a+car%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0Aclass+Truck+extends+Car+%7B%0D%0A++++void+load%28%29+%7B%0D%0A++++++++System.out.println%28%22Loading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++void+unload%28%29+%7B%0D%0A++++++++System.out.println%28%22Unloading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0A%2F%2F+Truck+reuses+driving+method%0D%0A%2F%2F+Overriding+it+would+be+another+code+smell%0D%0A%2F%2F+Violating+Liskov+Substitution+rule%0D%0A%60%60%60) | [ChatGPT](https://chat.openai.com/?q=1.+Identify+common+behaviors+in+both+classes+2.+Create+an+abstract+class+with+shared+behavior+and+no+implementation+3.+Move+common+logic+to+the+abstract+class+4.+Update+subclasses+to+inherit+from+the+abstract+class%3A+%60%60%60java%0D%0Aclass+Car+%7B%0D%0A++++void+drive%28%29+%7B%0D%0A++++++++System.out.println%28%22Driving+a+car%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0Aclass+Truck+extends+Car+%7B%0D%0A++++void+load%28%29+%7B%0D%0A++++++++System.out.println%28%22Loading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++void+unload%28%29+%7B%0D%0A++++++++System.out.println%28%22Unloading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0A%2F%2F+Truck+reuses+driving+method%0D%0A%2F%2F+Overriding+it+would+be+another+code+smell%0D%0A%2F%2F+Violating+Liskov+Substitution+rule%0D%0A%60%60%60) |
| [Claude](https://claude.ai/new?q=Correct+and+explain+this+code%3A+%60%60%60java%0D%0Aclass+Car+%7B%0D%0A++++void+drive%28%29+%7B%0D%0A++++++++System.out.println%28%22Driving+a+car%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0Aclass+Truck+extends+Car+%7B%0D%0A++++void+load%28%29+%7B%0D%0A++++++++System.out.println%28%22Loading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++void+unload%28%29+%7B%0D%0A++++++++System.out.println%28%22Unloading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0A%2F%2F+Truck+reuses+driving+method%0D%0A%2F%2F+Overriding+it+would+be+another+code+smell%0D%0A%2F%2F+Violating+Liskov+Substitution+rule%0D%0A%60%60%60) | [Claude](https://claude.ai/new?q=1.+Identify+common+behaviors+in+both+classes+2.+Create+an+abstract+class+with+shared+behavior+and+no+implementation+3.+Move+common+logic+to+the+abstract+class+4.+Update+subclasses+to+inherit+from+the+abstract+class%3A+%60%60%60java%0D%0Aclass+Car+%7B%0D%0A++++void+drive%28%29+%7B%0D%0A++++++++System.out.println%28%22Driving+a+car%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0Aclass+Truck+extends+Car+%7B%0D%0A++++void+load%28%29+%7B%0D%0A++++++++System.out.println%28%22Loading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++void+unload%28%29+%7B%0D%0A++++++++System.out.println%28%22Unloading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0A%2F%2F+Truck+reuses+driving+method%0D%0A%2F%2F+Overriding+it+would+be+another+code+smell%0D%0A%2F%2F+Violating+Liskov+Substitution+rule%0D%0A%60%60%60) |
| [Perplexity](https://perplexity.ai/?q=Correct+and+explain+this+code%3A+%60%60%60java%0D%0Aclass+Car+%7B%0D%0A++++void+drive%28%29+%7B%0D%0A++++++++System.out.println%28%22Driving+a+car%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0Aclass+Truck+extends+Car+%7B%0D%0A++++void+load%28%29+%7B%0D%0A++++++++System.out.println%28%22Loading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++void+unload%28%29+%7B%0D%0A++++++++System.out.println%28%22Unloading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0A%2F%2F+Truck+reuses+driving+method%0D%0A%2F%2F+Overriding+it+would+be+another+code+smell%0D%0A%2F%2F+Violating+Liskov+Substitution+rule%0D%0A%60%60%60) | [Perplexity](https://perplexity.ai/?q=1.+Identify+common+behaviors+in+both+classes+2.+Create+an+abstract+class+with+shared+behavior+and+no+implementation+3.+Move+common+logic+to+the+abstract+class+4.+Update+subclasses+to+inherit+from+the+abstract+class%3A+%60%60%60java%0D%0Aclass+Car+%7B%0D%0A++++void+drive%28%29+%7B%0D%0A++++++++System.out.println%28%22Driving+a+car%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0Aclass+Truck+extends+Car+%7B%0D%0A++++void+load%28%29+%7B%0D%0A++++++++System.out.println%28%22Loading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++void+unload%28%29+%7B%0D%0A++++++++System.out.println%28%22Unloading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0A%2F%2F+Truck+reuses+driving+method%0D%0A%2F%2F+Overriding+it+would+be+another+code+smell%0D%0A%2F%2F+Violating+Liskov+Substitution+rule%0D%0A%60%60%60) |
| [Copilot](https://www.bing.com/chat?showconv=1&sendquery=1&q=Correct+and+explain+this+code%3A+%60%60%60java%0D%0Aclass+Car+%7B%0D%0A++++void+drive%28%29+%7B%0D%0A++++++++System.out.println%28%22Driving+a+car%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0Aclass+Truck+extends+Car+%7B%0D%0A++++void+load%28%29+%7B%0D%0A++++++++System.out.println%28%22Loading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++void+unload%28%29+%7B%0D%0A++++++++System.out.println%28%22Unloading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0A%2F%2F+Truck+reuses+driving+method%0D%0A%2F%2F+Overriding+it+would+be+another+code+smell%0D%0A%2F%2F+Violating+Liskov+Substitution+rule%0D%0A%60%60%60) | [Copilot](https://www.bing.com/chat?showconv=1&sendquery=1&q=1.+Identify+common+behaviors+in+both+classes+2.+Create+an+abstract+class+with+shared+behavior+and+no+implementation+3.+Move+common+logic+to+the+abstract+class+4.+Update+subclasses+to+inherit+from+the+abstract+class%3A+%60%60%60java%0D%0Aclass+Car+%7B%0D%0A++++void+drive%28%29+%7B%0D%0A++++++++System.out.println%28%22Driving+a+car%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0Aclass+Truck+extends+Car+%7B%0D%0A++++void+load%28%29+%7B%0D%0A++++++++System.out.println%28%22Loading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++void+unload%28%29+%7B%0D%0A++++++++System.out.println%28%22Unloading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0A%2F%2F+Truck+reuses+driving+method%0D%0A%2F%2F+Overriding+it+would+be+another+code+smell%0D%0A%2F%2F+Violating+Liskov+Substitution+rule%0D%0A%60%60%60) |
| [Gemini](https://gemini.google.com/?q=Correct+and+explain+this+code%3A+%60%60%60java%0D%0Aclass+Car+%7B%0D%0A++++void+drive%28%29+%7B%0D%0A++++++++System.out.println%28%22Driving+a+car%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0Aclass+Truck+extends+Car+%7B%0D%0A++++void+load%28%29+%7B%0D%0A++++++++System.out.println%28%22Loading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++void+unload%28%29+%7B%0D%0A++++++++System.out.println%28%22Unloading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0A%2F%2F+Truck+reuses+driving+method%0D%0A%2F%2F+Overriding+it+would+be+another+code+smell%0D%0A%2F%2F+Violating+Liskov+Substitution+rule%0D%0A%60%60%60) | [Gemini](https://gemini.google.com/?q=1.+Identify+common+behaviors+in+both+classes+2.+Create+an+abstract+class+with+shared+behavior+and+no+implementation+3.+Move+common+logic+to+the+abstract+class+4.+Update+subclasses+to+inherit+from+the+abstract+class%3A+%60%60%60java%0D%0Aclass+Car+%7B%0D%0A++++void+drive%28%29+%7B%0D%0A++++++++System.out.println%28%22Driving+a+car%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0Aclass+Truck+extends+Car+%7B%0D%0A++++void+load%28%29+%7B%0D%0A++++++++System.out.println%28%22Loading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++void+unload%28%29+%7B%0D%0A++++++++System.out.println%28%22Unloading+cargo%22%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%0D%0A%2F%2F+Truck+reuses+driving+method%0D%0A%2F%2F+Overriding+it+would+be+another+code+smell%0D%0A%2F%2F+Violating+Liskov+Substitution+rule%0D%0A%60%60%60) | 

# Tags

- Inheritance

# Related Refactorings

%[https://maximilianocontieri.com/refactoring-013-remove-repeated-code]

# See also

%[https://refactoring.guru/es/extract-superclass]

# Credits

Image by [Pexels](https://pixabay.com/users/pexels-2286921/) on [Pixabay](https://pixabay.com//)

* * * 

This article is part of the Refactoring Series.

%[https://maximilianocontieri.com/how-to-improve-your-code-with-easy-refactorings]
