I have the following situation in my application:
- I have a service class with 700+ lines
- The class is responsible for data aggregation from different sources.
- There is no real signature in the inputs, as I mentioned in the code example.
- The service will collect the data sequentially and sometimes we should ignore some method based on specific condition.
- Currently the code become unmaintainable since the logic is growing and become more and more complex.
- I already have looked into pipeline and Chain of Responsibility design pattern
- pipeline: I think it will not resolve my issue, since the output from step1 is not necessary to be an input for step2
- Chain of Responsibility: also this pattern will not fix the issue since the input signature is different.
Could you please suggest away to refactor the code in order to make things clear and maintainable.
public class DataCollector{
public Report collect(input1){
Report report = new Report();
report.setFirstPart(getFirstPart(input1));
report.setSecondPart(getSecondPart(report.getFirstPart().getInput2()));
report.setThirdPart(getThirdPart(input1, report.getSecondPart().getInput3()));
report.setFourthPart(input1, report.getFirstPart().getInput2());
if( input1 > report.getSecondPart().getInput3()){
report.setFifthPart(report.getFirstPart().getInput2());
}
else{
report.setSixthPart(input1, report.getSecondPart().getInput3(), report.getThirdPart().getInput4());
}
return report;
}
public FirstPart getFirstPart(input1){
...method logic(retrieve from DB or call service either rest or soap)
}
public SecondPart getSecondPart(input2){
...method logic(retrieve from DB or call service either rest or soap)
}
public ThirdPart getThirdPart(input1, input3){
...method logic(retrieve from DB or call service either rest or soap)
}
public FourthPart getFourthPart(input1, input2){
...method logic(retrieve from DB or call service either rest or soap)
}
public FifthPart getFifthPart(input2){
...method logic(retrieve from DB or call service either rest or soap)
}
public sixthPart getSixthPart(input1, input3, input4){
...method logic(retrieve from DB or call service either rest or soap)
}
}
Given that the way you aggregate the data is not simple or straightforward I would say that there is no silver bullet for your case, other than the Orchestration pattern which is basically what you have with minor adjustments.
Basically, your
DataCollectorclass should be responsible to orchestrate the data collection operation, but it shouldn't do it itself but instead rely on other more specialized classes for each "part" as you call it.Having said that, I would suggest you keep the
collect()method in theDataCollectorclass but move each (or maybe multiple if it makes sense) of the other methods for data retrieval to their own specialized classes. This way you can simplifyDataCollectormaking it manageable and keep all the remaining complexity in smaller classes as well.