mardi 22 décembre 2020

What design pattern to use for a common method with multiple implementations having different input parameter and different return type?

I am new to design patterns, and thus have a limited knowledge of what all is available. I am trying to implement a solution for a problem and request the user community to give some guidance on what design pattern to use and how it should be implemented.

Task : Implement central mapping factory that takes some input x and converts it to some output y. New implementation can be added in future.

  1. Input parameter is different for each implementation
  2. Ouput parameter type is different for each implementation

So far I have implemented factory pattern but I am doubtful on following points:

  • Warning in MapperFactory Raw use of parameterized class MappingUtil
  • In the service class when I use factory mapperFactory.getMappingUtils("A").mapData(a) I have to cast the output since each implementation has it's own specific outputformat

Is this the correct approach to the problem or am I following any anti-pattern in the implementation

public interface MappingUtil<X, Y> {
    Y mapData (X value);
}
 
@Component
public class A implements MappingUtil<Input A, OutputA> {

    @Override
    public OutputA mapData(Input A){
    // Perform some logic and convert InputA to OutputA and return Output A object
    }
   }

@Component
public class B implements MappingUtil<Input B, OutputB> {

    @Override
    public OutputB mapData(Input B){
    // Perform some logic and convert InputB to OutputB and return OutputB object
    }
   }

@Component
public class C implements MappingUtil<Input C, OutputC> {

    @Override
    public OutputC mapData(Input C){
    // Perform some logic and convert InputC to OutputC and return OutputC object
    }
   }
}

Factory Class

@Component
public class MapperFactory {

private final static Logger LOGGER = LoggerFactory.getLogger(MapperFactory.class);
private static Map<String, MappingUtil> mapperStrategyMapping;

private final A a;
private final B b;
private final C c;

@PostConstruct
void init() {
    mapperStrategyMapping = new HashMap<>();
    mapperStrategyMapping.put("A", a);
    mapperStrategyMapping.put("B", b);
    mapperStrategyMapping.put("C", c);
}

@Autowired
MapperFactory(A a,
              B b,
              C c) {
    this.a = a;
    this.b = b;
    this.c = c;
}

public MappingUtil getMappingUtil(String mapperCode) throws Exception {
    if (mapperCode != null) {
        return mapperStrategyMapping.get(mapperCode);
    } else {
        LOGGER.error("Empty mapper code received");
        throw new Exception("Empty mapper code");
    }
}

Usage of Factory :

@Service
public class XyzImpl implements Xyz{

    private final MapperFactory mapperFactory;

    @Autowired
    XyzImpl(MapperFactory mapperFactory){
        this.mapperFactory = mapperFactory;
    } 

    public void doFunction1(Input a , Input b){
        OutputA outputA = (Output A) mapperFactory.getMappingUtils("A").mapData(a);
        OutputB outputB = (Output B) mapperFactory.getMappingUtils("B").mapData(b);
        // Perform some logic on Output A Output B
    }

    public void doFunction2(Input c){
        OutputC outputC = (Output C) mapperFactory.getMappingUtils("C").mapData(c);
        // Perform some logic on Output C
    }
}

Aucun commentaire:

Enregistrer un commentaire