4

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

Beginner
  • 145
  • 7

2 Answers2

3

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.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Rami Del Toro
  • 1,130
  • 9
  • 24
0

Your case has nothing to do with SOLID. According to open-closed principle, you cannot allow modification to your class IN RUNTIME that can break its behavior.

In your case I suggest the following:

  • Add getId() method to your TemplateClassification interface.

  • Make each TemplateClassification implementation a bean

  • Add bean that will form the map of templates for you

      @Bean
      public Map<Integer, TemplateClassification> templates(List<TemplateClassification> templates) {
      return algorithms.stream()
          .collect(Collectors.toMap(TemplateClassification::getId, Function.identity()));
      }
    
  • Autowire Map<Integter, TemplateClassification> templates to your controller and find the required template by id.

Sergiy Dakhniy
  • 538
  • 1
  • 4
  • 15