According to the SOLID principle open and close principle says class is open for extension and closed for modification.
So I am allowed to add new logic based on new if-else conditions?
If I will not use conditionals so how will I identify based on which condition which action has to be applied
public interface TemplateClassification {
QuesObj processTemplate(RawPart rawPart);
}
public class Template1 implements TemplateClassification{
@Override
public QuesObj processTemplate(RawPart rawPart) {
return new QuesObj("Hi header 1"+rawPart.getHead(),"Hi I am footer 1"+rawPart.getFoot());
}
}
public class Template2 implements TemplateClassification{
@Override
public QuesObj processTemplate(RawPart rawPart) {
return new QuesObj("Hi header 2"+rawPart.getHead(),"Hi I am footer "+rawPart.getFoot());
}
}
public class TemplateInfo {
private TemplateClassification templateClassification;
public TemplateClassification getTemplateClassification() {
return templateClassification;
}
public void setTemplateClassification(TemplateClassification templateClassification) {
this.templateClassification = templateClassification;
}
}
public class TemplateProduct {
public QuesObj calculateTemplate(TemplateInfo templateInfo,RawPart rawPart){
QuesObj ques = templateInfo.getTemplateClassification().processTemplate(rawPart);
return ques;
}
}
@RestController
class Pg {
@Autowired
TemplateInfo templateInfo;
@Autowired
TemplateProduct templateProduct;
public doProcessing(RawPart rawPart){
QuesObj ques = null;
if(rawPart.getId() == 1){
Template1 temp = new Template1();
ques = templateProduct.calculateTemplate(templateInfo,rawPart);
}
elseIf(rawPart.getId() == 2){
Template2 temp = new Template2();
ques = templateProduct.calculateTemplate(templateInfo,rawPart);
}
elseIf(tempId == 3){
// coming soon
}
}
}
How can i eliminte the if else condition so that it can follow open-close principle
To implement the "O" in SOLID, you can follow the below, which includes the "S" as well.
We are going to use polymorphism and inheritance.
Step 1 :
Create an interface that will sit in front of the classes that will be responsible in creating the QuesObj. We are going to need this, because down the line the code could receive a creator (child class) when id is 1,2 or 3.
It is important to note that QuesObj was identified because that is being returned on your original if statements and this is the reason we are allowed to continue with this approach.
public interface QuesObjCreator {
QuesObj calculate(RawPart rawPart);
}
Step 2:
Create individual class that creates the QuesObj in different ways in The only role of that class is to create the object.
public class QuesObjCreatorFor1 implements QuesObjCreator {
private TemplateInfo templateInfo;
private TemplateProduct templateProduct;
@Override
public QuesObj calculate(RawPart rawPart) {
Template1 temp = new Template1();
return templateProduct.calculateTemplate(templateInfo,rawPart);
}
}
public class QuesObjCreatorFor2 implements QuesObjCreator {
private TemplateInfo templateInfo;
private TemplateProduct templateProduct;
@Override
public QuesObj calculate(RawPart rawPart) {
Template2 temp = new Template2();
return templateProduct.calculateTemplate(templateInfo,rawPart);
}
}
Step 3:
Create a factory to return a QuesObjCreator. The factory will be returned to your main code/service.
public class QuesObjectCreatorFactory {
private static final Map<Integer,QuesObjCreator> quesObjCreatorMap = new HashMap<>();
public QuesObjectCreatorFactory() {
quesObjCreatorMap.put(1,new QuesObjCreatorFor1());
quesObjCreatorMap.put(2,new QuesObjCreatorFor2());
}
public static QuesObjCreator getQuesObjCreator(final int number) {
final QuesObjCreator quesObjCreator = quesObjCreatorMap.get(number);
if(quesObjCreator == null) {
throw new IllegalArgumentException("QuesObj for "+number+" does not exist");
}
return quesObjCreator;
}
}
Step 4:
Use Factory to create the QuesObj
public class Pg {
public void doProcessing(RawPart rawPart){
final QuesObjCreator quesObjCreator = QuesObjectCreatorFactory.getQuesObjCreator(rawPart.getId());
QuesObj ques = quesObjCreator.calculate(rawPart);
}
}
Collectively we achieved the Single responsibility across all classes and are decoupled.
It is easy to maintain cause now you can add more options to create QuesObj and none of the code would change, thus achieving open for extensibility/closed for modification.
It all boils down to the Factory and Map that has the creators. The map has to be populated with all the creator instances. With Spring this can be very easy, as Spring can scan your project, find beans of a specific type, give you a List and then you can convert it to a map.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With