lundi 30 septembre 2024

Multimplémentation et l'injection de dépendance.

Dans cet article,  nous montrons une approche afin d'avoir un seul endpoint lorsque vous avez différent type de donnée en entrée ou sortie. Cela permet aussi de faire du traitement différent pour chacun des types.


Définition des types de données

C'est une des nombreuses possibilités de la librairie Jackson qui est montrée ici.

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", include = JsonTypeInfo.As.EXISTING_PROPERTY, visible = true)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Square.class, name = "SQUARE"),
    @JsonSubTypes.Type(value = Circle.class, name = "CIRCLE"),
})

@Data
public abstract class Shape {
    public String type;
}


@JsonTypeName("SQUARE")
@Data
public class Square extends Shape {
   public double length;
}

@JsonTypeName("CIRCLE")
@Data
public class Circle extends Shape {
   public double radius;
}


Définition des services pour les types de données

Puisque le traitement peut être différent pour chaque type de données,  un service est créé pour chacun d'eux.

public interface IShapeService<T extends Shape> {
    T saveShape(T t);
}

@Service("SQUARE_SERVICE")
public class SquareShapeService  implements IShapeService<Shape> {
    public Square save(Square square){
         return square;
    }

}

@Service("CIRCLE_SERVICE")
public class CircleShapeService  implements IShapeService<Circle> {
    public Circle save(Circle circle){
         return circle;
    }
}

S'il y a du code commun, les classes implémentant IShapeService pourrait hériter d'une autre classe. Sinon, la composition pourrait être utilisée.

En affectant une valeur pour les différents services et en voyant qu'ils implémentent IShapeService, Spring sera qu'il doit mettre le nom du service comme clé et les instances comme valeur dans la Map.

Il faut faire le pont entre le type de donnée entrée et le service à appeler. Il serait possible d'utiliser une enum. 

Donc si on passe le type SQUARE, on concatène "_SERVICE" afin d'obtenir l'instance de SquareShapeService dans la map

@Service
public class ShapeService{
   private final Map<String, IShapeService> shapeServiceMap;

     public Shape save(Shape shape) {
        IShapeService service = shapeServiceMap.get(shape.getType() + _"SERVICE");
        return service.save(shape);
    }  
}


@RequiredArgsConstructor
@RestController
@RequestMapping(value = "/shapes")
public class ShapeController {

   private ShapeService shapeService;

    @PostMapping("")
    public ResponseEntity<Shape> save(@RequestBody Shape shape) {
        return new ResponseEntity<>(shapeService.save(shape), HttpStatus.OK);

    }
}


Il est donc possible de Passer un objet de type square ou circle à ce contrôleur

Aucun commentaire:

Enregistrer un commentaire