What is the meaning of the Composing method?
The “Composing method” is part of refactoring techniques and much of refactoring is devoted to the “Composing method”. In most cases the long method is the root cause of all evil, so the “Composing method” aims to break down into small and more focused methods. It removes code duplication and enhances code quality.
> Extract Method > Inline Method > Extract Variable > Inline Temp > Replace Temp with Query > Split Temporary Variable > Remove Assignments to Parameters > Replace Method with Method Object > Substitute Algorithm
Extract method
In this refactoring technique which is part of the Composing method, the developer takes a portion of code from a long method and moves it into a separate one. When a method performs different operations, the takes each operation from the larger method and keeps them into separate methods. It improves the code readability, and reusability, and reduces code duplication. Let’s see it with an example of the refactor extract method
Problem
Suppose you are working on a project and you find a class, where the main method performs different operations like code calculates the subtotal, applies the discount, and calculates the total. It’s hard to read and analyze the responsibility of the method.
public class ShoppingCart { public static void main(String[] args) { double item1Price = 20.0; double item2Price = 30.0; double item3Price = 15.0; double subtotal = item1Price + item2Price + item3Price; double discount = 0.0; if (subtotal > 50.0) { discount = subtotal * 0.1; } double total = subtotal - discount; System.out.println("Subtotal: $" + subtotal); System.out.println("Discount: $" + discount); System.out.println("Total: $" + total); } }
We created three separate methods (calculateSubtotal, calculateDiscount, and calculateTotal) and simplified the code. Each method will perform a different operation.
public class ShoppingCartRefactored { public static void main(String[] args) { double item1Price = 20.0; double item2Price = 30.0; double item3Price = 15.0; double subtotal = calculateSubtotal(item1Price, item2Price, item3Price); double discount = calculateDiscount(subtotal); double total = calculateTotal(subtotal, discount); System.out.println("Subtotal: $" + subtotal); System.out.println("Discount: $" + discount); System.out.println("Total: $" + total); } // Extracted methods for better readability and reusability private static double calculateSubtotal(double item1Price, double item2Price, double item3Price) { return item1Price + item2Price + item3Price; } private static double calculateDiscount(double subtotal) { if (subtotal > 50.0) { return subtotal * 0.1; } return 0.0; } private static double calculateTotal(double subtotal, double discount) { return subtotal - discount; } }
Why did we refactor?
It’s hard to find the objective of a long method when it performs multiple operations. It probably increases the code duplication if a similar calculation is needed somewhere else.
Advantages
- It has increased the readability of the problem and made sure the method names should describe the method’s purpose.
- There is very little chance for code duplication as the code is found in the method and that can be reused in other places of the program.
- One method is performing only one type of operation that leads to the isolation of independent parts of the code.
Inline method
A developer should use this technique when a method body is more obvious than the method itself. In this technique, we can replace a method call with the actual code contained within that method. Confused? This line of statement can create confusion because in the extract method, we said, we should create a method for each operation. I will explain it at the end of this point, till then focus on the inline method
Problem
In this program, we have two methods those are main () method and the calculateSquare() method. But here you can see, that the calculateSquare () method’s body is more obvious than the method itself. We can directly write the code instead of calling the calculateSquare() method. This method is very small and doesn’t provide significant abstraction.
public class MathOperations { public static void main(String[] args) { int number = 5; int square = calculateSquare(number); System.out.println("The square of " + number + " is: " + square); } private static int calculateSquare(int number) { return number * number; } }
Here we have eliminated the calculatedSquare() method and performed calculation operations within the main method. Since the method was simple.
public class MathOperationsRefactored { public static void main(String[] args) { int number = 5; int square = number * number; // Inlined method call System.out.println("The square of " + number + " is: " + square); } }
Why did we refactor?
Methods shouldn’t be too short, because if you have a lot of short methods it can get messy and confusing. Sometimes, methods were more useful in the past, but as you made changes to your program, they became less important. It helps keep your code clean and easy to understand.
Advantages
By minimizing the number of unneeded methods, you make the code more straightforward.
Extract method Vs Inline method
Let us take 2 examples and see when we should use the extract method or insert method.
First Example
public class ShoppingCart { public static void main(String[] args) { double item1Price = 20.0; double item2Price = 30.0; double item3Price = 15.0; double subtotal = calculateSubtotal(item1Price, item2Price, item3Price); double discount = calculateDiscount(subtotal); double tax = calculateTax(subtotal); double total = calculateTotal(subtotal, discount, tax); System.out.println("Subtotal: $" + subtotal); System.out.println("Discount: $" + discount); System.out.println("Tax: $" + tax); System.out.println("Total: $" + total); } // Extracted methods for better readability and abstraction private static double calculateSubtotal(double item1Price, double item2Price, double item3Price) { return item1Price + item2Price + item3Price; } private static double calculateDiscount(double subtotal) { return subtotal > 50.0 ? subtotal * 0.1 : 0.0; } private static double calculateTax(double subtotal) { return subtotal * 0.07; } private static double calculateTotal(double subtotal, double discount, double tax) { return subtotal - discount + tax; } }
Why should we use the extract method here?
Imagine we have a program that performs calculation operations. A program that calculates the total cost of items in a shopping cart, including discounts and taxes. Of course, the calculation involves several steps. So, we should use the Extract Method because it enhances readability and maintains a clear level of abstraction.
Why should not Use the Inline Method here?
Look at the program and imagine if we replace the extracted methods with inline methods. You will see a lot of calculations in the main method and it will be less readable and less maintainable code. As calculation has multiple steps, extracting methods provide clarity and abstraction to each step.
Example 2:
public class MathOperationsRefactored { public static void main(String[] args) { int number = 5; int square = number * number; // Inlined method call System.out.println("The square of " + number + " is: " + square); } }
Why should we use the inline method here?
Let’s take an example that calculates the square of a number. So, the calculation is simple and involves only one operation. In this case, we don’t need to extract the method, if we are using that we should replace it with the inline method.
Why should not Use the extract Method here?
In the above scenario, if we use the Extract Method for this simple calculation it considers unnecessary abstraction and overhead. The calculation is concise and doesn’t require a separate method to improve readability.
Replace Temp with Query
A developer can apply this refactoring technique if we have a place, where the result of expression is stored in a local variable and then it is used. In this technique, we replace the temporary variables with a direct call to the method or expression.
Problem
Let’s take an example, that calculates the final price of a product after applying the discount. Here we have a temporary variable (subtotal, discount, total) to store the result of the sub-total price of items, discount, and total price of items. If you look at them carefully, you will notice the variable total is used only once and doesn’t enhance code readability or maintainability.
public class ShoppingCartRefactored { public static void main(String[] args) { double item1Price = 20.0; double item2Price = 30.0; double item3Price = 15.0; double subtotal = calculateSubtotal(item1Price, item2Price, item3Price); double discount = calculateDiscount(subtotal); double total = subtotal - discount; System.out.println("Subtotal: $" + subtotal); System.out.println("Discount: $" + discount); System.out.println("Total: $" + total); } // Extracted methods for better readability and reusability private static double calculateSubtotal(double item1Price, double item2Price, double item3Price) { return item1Price + item2Price + item3Price; } private static double calculateDiscount(double subtotal) { if (subtotal > 50.0) { return subtotal * 0.1; } return 0.0; } }
After applying the refactoring technique, we have removed the temporary variables (total). The calculatedTotal() method performs the operation and returns the final price. We have eliminated the temporary variable and now the code is more concise.
public class ShoppingCartRefactored { public static void main(String[] args) { double item1Price = 20.0; double item2Price = 30.0; double item3Price = 15.0; double subtotal = calculateSubtotal(item1Price, item2Price, item3Price); double discount = calculateDiscount(subtotal); System.out.println("Subtotal: $" + subtotal); System.out.println("Discount: $" + discount); System.out.println("Total: $" + calculateTotal(subtotal, discount)); } // Extracted methods for better readability and reusability private static double calculateSubtotal(double item1Price, double item2Price, double item3Price) { return item1Price + item2Price + item3Price; } private static double calculateDiscount(double subtotal) { if (subtotal > 50.0) { return subtotal * 0.1; } return 0.0; } private static double calculateTotal(double subtotal, double discount) { return } }
Advantages:
It is much easier to understand the purpose the of calculateTotal() method instead of the previous code. It increases the readability of the code.