Methods to Refactor Quadratic Equation Solvers in Java with Cleaner OOP Code
When tackling the challenge of solving quadratic equations, many Java developers initially adopt procedural coding approaches that quickly become cumbersome as complexity increases. This article explores methods for refactoring quadratic equation...

I am Tuanh.net. As of 2024, I have accumulated 8 years of experience in backend programming. I am delighted to connect and share my knowledge with everyone.
1. Understanding the Problem
public class QuadraticSolver {
public static void main(String[] args) {
double a = 1, b = -3, c = 2; // Example coefficients
double determinant = b b - 4 a c;
if (determinant > 0) {
double root1 = (-b + Math.sqrt(determinant)) / (2 a);
double root2 = (-b - Math.sqrt(determinant)) / (2 a);
System.out.println("Roots are: " + root1 + " and " + root2);
} else if (determinant == 0) {
double root = -b / (2 a);
System.out.println("Root is: " + root);
} else {
System.out.println("No real roots.");
}
}
}
1.1 Why Refactor?
- Hard to Extend: Adding features like logging or validation requires intrusive changes.
- Poor Reusability: Code specific to one use case cannot be easily reused.
- Limited Scalability: Debugging or modifying becomes tedious as the logic grows.
1.2 Key Principles of Clean OOP Design
- Single Responsibility Principle (SRP): Each class should have one responsibility.
- Open-Closed Principle (OCP): Classes should be open for extension but closed for modification.
- Encapsulation: Hide implementation details, exposing only necessary functionality.
- Polymorphism: Use abstraction to eliminate conditional logic where possible.
1.3 First Refactor: Introducing a QuadraticEquation Class
public class QuadraticEquation {
private double a, b, c;
public QuadraticEquation(double a, double b, double c) {
if (a == 0) {
throw new IllegalArgumentException("Coefficient 'a' cannot be zero for a quadratic equation.");
}
this.a = a;
this.b = b;
this.c = c;
}
public double getA() {
return a;
}
public double getB() {
return b;
}
public double getC() {
return c;
}
public double calculateDeterminant() {
return b b - 4 a * c;
}
}
1.4 Refactoring Solvers with Polymorphism
public interface RootSolver {
void solve(QuadraticEquation equation);
}
public class RealRootSolver implements RootSolver {
@Override
public void solve(QuadraticEquation equation) {
double determinant = equation.calculateDeterminant();
if (determinant > 0) {
double root1 = (-equation.getB() + Math.sqrt(determinant)) / (2 equation.getA());
double root2 = (-equation.getB() - Math.sqrt(determinant)) / (2 equation.getA());
System.out.println("Roots are: " + root1 + " and " + root2);
} else if (determinant == 0) {
double root = -equation.getB() / (2 * equation.getA());
System.out.println("Root is: " + root);
} else {
System.out.println("No real roots.");
}
}
}
2. Extending the Design
2.1 Handling Complex Roots
public class ComplexRootSolver implements RootSolver {
@Override
public void solve(QuadraticEquation equation) {
double determinant = equation.calculateDeterminant();
if (determinant < 0) {
double realPart = -equation.getB() / (2 equation.getA());
double imaginaryPart = Math.sqrt(-determinant) / (2 equation.getA());
System.out.println("Roots are: " + realPart + " ± " + imaginaryPart + "i");
}
}
}
2.2 Factory for Solver Selection
public class RootSolverFactory {
public static RootSolver getSolver(QuadraticEquation equation) {
double determinant = equation.calculateDeterminant();
if (determinant >= 0) {
return new RealRootSolver();
} else {
return new ComplexRootSolver();
}
}
}
2.3 Putting It All Together
public class QuadraticEquationSolverApp {
public static void main(String[] args) {
QuadraticEquation equation = new QuadraticEquation(1, -3, 2); // Example coefficients
RootSolver solver = RootSolverFactory.getSolver(equation);
solver.solve(equation);
}
}
3. Benefits of Refactoring
- Readability: Each class has a clear, single responsibility.
- Reusability: Solvers can be used across multiple projects.
- Extensibility: Adding new solvers (e.g., symbolic solutions) requires no changes to existing classes.
3.1 Best Practices
- Test Each Component: Write unit tests for individual classes like QuadraticEquation and solvers.
- Follow Naming Conventions: Use descriptive names for methods and classes.
- Document Intent: Add comments to explain critical logic.
3.2 Challenges and Solutions
- Handling Edge Cases: Ensure coefficients are validated at construction.
- Performance: Use caching if determinant calculations are repeated.
4. Conclusion
Read more at : Methods to Refactor Quadratic Equation Solvers in Java with Cleaner OOP Code





