Mastering Code Refactoring: From Repetition to Design Patterns in Java
This article walks through a step‑by‑step refactoring of repetitive Java code, illustrating how to extract common methods, use reflection, apply generics with lambda expressions, leverage inheritance and the template method pattern, and finally combine factory, template, and strategy patterns into a clean, reusable solution.
1. Example Before Optimization
The initial scenario simulates a reconciliation task that reads files from two endpoints (A and B), converts them into lists, transforms the lists into maps using a unique key, and then compares each field of the resulting maps.
<code>private void checkDetail(String detailPathOfA,String detailPathOfB) throws IOException {
// Read A side file
List<DetailDTO> resultListOfA = new ArrayList<>();
try (BufferedReader reader1 = new BufferedReader(new FileReader(detailPathOfA))) {
String line;
while ((line = reader1.readLine()) != null) {
resultListOfA.add(DetailDTO.convert(line));
}
}
// Read B side file
List<DetailDTO> resultListOfB = new ArrayList<>();
try (BufferedReader reader1 = new BufferedReader(new FileReader(detailPathOfB))) {
String line;
while ((line = reader1.readLine()) != null) {
resultListOfB.add(DetailDTO.convert(line));
}
}
// Convert A list to map
Map<String,DetailDTO> resultMapOfA = new HashMap<>();
for(DetailDTO detail:resultListOfA){
resultMapOfA.put(detail.getBizSeq(),detail);
}
// Convert B list to map
Map<String,DetailDTO> resultMapOfB = new HashMap<>();
for(DetailDTO detail:resultListOfB){
resultMapOfB.put(detail.getBizSeq(),detail);
}
// Compare each entry
for (Map.Entry<String, DetailDTO> temp : resultMapOfA.entrySet()) {
if (resultMapOfB.containsKey(temp.getKey())) {
DetailDTO detailOfA = temp.getValue();
DetailDTO detailOfB = resultMapOfB.get(temp.getKey());
if (!detailOfA.getAmt().equals(detailOfB.getAmt())) {
log.warn("amt is different,key:{}", temp.getKey());
}
if (!detailOfA.getDate().equals(detailOfB.getDate())) {
log.warn("date is different,key:{}", temp.getKey());
}
if (!detailOfA.getStatus().equals(detailOfB.getStatus())) {
log.warn("status is different,key:{}", temp.getKey());
}
// ... other field checks
}
}
}
</code>2. Extract Common Method to Remove Duplication
Identify duplicated code such as file reading and list‑to‑map conversion, and extract them into reusable methods like
readFileand
convertListToMap.
3. Use Reflection for Field Comparison
When objects have many fields, reflection can automate the field‑by‑field comparison, reducing boilerplate code.
4. Combine Lambda Expressions and Generics
Abstract the file‑reading logic with a generic method that accepts a lambda to convert each line, enabling reuse for both detail and balance files.
<code>private void checkDetail(String detailPathOfA, String detailPathOfB) throws IOException {
List<DetailDTO> resultListOfA = readDataFromFile(detailPathOfA, DetailDTO::convert);
List<DetailDTO> resultListOfB = readDataFromFile(detailPathOfB, DetailDTO::convert);
Map<String, DetailDTO> resultMapOfA = convertListToMap(resultListOfA);
Map<String, DetailDTO> resultMapOfB = convertListToMap(resultListOfB);
compareDifferent(resultMapOfA, resultMapOfB);
}
private void checkBalance(String balancePathOfA, String balancePathOfB) throws IOException {
List<BalanceDTO> resultListOfA = readDataFromFile(balancePathOfA, BalanceDTO::convert);
List<BalanceDTO> resultListOfB = readDataFromFile(balancePathOfB, BalanceDTO::convert);
Map<String, BalanceDTO> resultMapOfA = convertListToMap(resultListOfA);
Map<String, BalanceDTO> resultMapOfB = convertListToMap(resultListOfB);
compareDifferent(resultMapOfA, resultMapOfB);
}
private <T> void compareDifferent(Map<String, T> mapA, Map<String, T> mapB) {
for (Map.Entry<String, T> temp : mapA.entrySet()) {
if (mapB.containsKey(temp.getKey())) {
T dtoA = temp.getValue();
T dtoB = mapB.get(temp.getKey());
List<String> resultList = compareObjects(dtoA, dtoB);
for (String diff : resultList) {
log.warn("{} is different,key:{}", diff, ((BaseDTO)dtoA).getKey());
}
}
}
}
</code>5. Apply Inheritance and Polymorphism
Define an abstract class
BaseKeyDTOwith an abstract
getKeymethod. Let both
BalanceDTOand
DetailDTOextend it, enabling generic handling of different DTO types.
6. Template Method Pattern
Both detail and balance comparison share the same algorithm skeleton: read files, convert to lists, transform to maps, and compare fields. The template method abstracts this skeleton, allowing subclasses to provide specific conversion logic.
6.1 Define the Comparison Template
Declare an abstract class with a
readDataFromFilemethod that returns a
Pairof lists, and an abstract
convertLineToDTDfor subclasses to implement.
7. Combine Factory, Template Method, and Strategy Patterns
Create an
ICheckStrategyinterface and implement concrete strategies for detail and balance checks. Use a Spring factory to map strategy enums to implementations, allowing callers to select the appropriate check at runtime.
<code>/** Detail check strategy */
@Service
public class CheckDetailStrategyServiceImpl extends AbstractCheckTemplate<DetailDTO> {
@Override
protected DetailDTO convertLineToDTD(String line) {
return DetailDTO.convert(line);
}
@Override
public void check(String filePathA, String filePathB) throws IOException {
checkTemplate(filePathA, filePathB);
}
@Override
public CheckEnum getCheckEnum() {
return CheckEnum.DETAIL_CHECK;
}
}
/** Balance check strategy */
@Service
public class CheckBalanceStrategyServiceImpl extends AbstractCheckTemplate<BalanceDTO> {
@Override
protected BalanceDTO convertLineToDTD(String line) {
return BalanceDTO.convert(line);
}
@Override
public void check(String filePathA, String filePathB) throws IOException {
checkTemplate(filePathA, filePathB);
}
@Override
public CheckEnum getCheckEnum() {
return CheckEnum.BALANCE_CHECK;
}
}
</code>By leveraging Spring's
ApplicationContextAware, the strategies are registered in a map, and a unified
checkComparemethod dispatches the appropriate strategy, demonstrating the practical use of factory, template, and strategy patterns together.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.