Search code examples
javadesign-patternsjakarta-eecdisoftware-design

What is the name of the design pattern where I dynamically pick the correct implementation based on data?


Originally I picked the correct User implementation, based on domain and realm data from the Java EE server. However that was company code, so I had to rewrite the example with numbers. I hope the underlying pattern is still understandable though. For those unfamiliar with CDI, @Inject Instance allows you to iterate through all implementations of an interface.

public class NumberPicker {

    @Inject
    private Instance<NumberMapper> mappers;

    public Number parse (String string) {
        for( NumberMapper mapper : mappers ){
            if( mapper.isApplicable(string) ){
                return mapper.apply(string);
            }
        }
        throw new InvalidArgumentException("Can not parse " + string);
    }

}

public interface NumberMapper {

    boolean isApplicable (String string);

    Number apply (String string);

}

public class ByteMapper implements NumberMapper {

    @Override
    public boolean isApplicable (String string) {
        return string.length() == 1;
    }

    @Override
    public Number apply (String string) {
        return (byte) string.charAt(0);
    }

}

public class IntegerMapper implements NumberMapper {

    @Override
    public boolean isApplicable (String string) {
        if( string.length() == 1 ){
            return false;
        }
        try {
            Integer.parseInt(string);
            return true;
        }catch( NumberFormatException e ){
            return false;
        }
    }

    @Override
    public Number apply (String string) {
        return Integer.parseInt(string);
    }

}

public class FloatMapper implements NumberMapper

    @Override
    public boolean isApplicable (String string) {
        if( string.length() == 1 ) {
            return false;
        }
        try {
            Integer.parseInt(string);
            return false;
        }catch( NumberFormatException e){
        }
        try {
            Float.parseFloat(string);
            return true;
        }catch( NumberFormatException e){
            return false;
        }
    }

    @Override
    public Number apply (String string) {
        return Float.parseFloat(string);
    }

}

Solution

  • I think you are talking about the Strategy Pattern:

    public interface Strategy {
       boolean test();
       void execute();
    }
    
    public class FirstStrategy implements Strategy{
       @Override
       public boolean test() {
          //returns true or false
       }
    
       @Override
       public void execute() {
           //your custom implementation
       }
    }
    
    
    public class SecondStrategy implements Strategy{
       @Override
       public boolean test() {
          //returns true or false
       }
    
       @Override
       public void execute() {
           //your custom implementation
       }
    }
    

    Then you have your list of strategies:

    List<Strategy> strategiesList = List.of(new FirstStrategy(), new SecondStrategy());
    

    Thus:

    strategiesList.stream()
        .filter(aStrategy -> aStrategy.test())
        .findFirst()
        .ifPresent(aStrategy -> aStrategy.execute());