Problème : Nous avons deux librairies CoolGraphics et SimpleGraphics qui sont fonctionnellement équivalentes et on veut pouvoir utiliser l'une ou l'autre.
Solution : L'idée générale est de créer une troisième librairie (que l'on choisit ici d'appeler Canvas) que l'on va être capable de coder en utilisant CoolGraphics et SimpleGraphics.
Si vous êtes bloqué, le slide suivant vous donne un exemple de l'interface Canvas.
public interface Canvas {
enum CanvasColor {
BLACK,WHITE,ORANGE;
}
@FunctionalInterface
interface MouseClickCallBack{
void onClick(int x,int y);
}
void clear(CanvasColor c);
void drawLine(int x1,int y1,int x2,int y2,CanvasColor c);
void drawEllipse(int x,int y,int width,int height,CanvasColor c);
void waitForMouseClick(MouseClickCallBack callback);
default void drawRectangle(int x,int y,int width,int height,CanvasColor c){
drawLine(x,y,x+width,y,c);
drawLine(x,y+height,x+width,y+height,c);
drawLine(x,y,x,y+height,c);
drawLine(x+width,y,x+width,y+height,c);
}
}
Il y a plusieurs questions auxquelles il faut savoir répondre:
Color de CoolGraphics ? BiConsumer<Interger,Integer> à la place de définir une
interface fonctionnelle ? drawRectangle est en default.Canvas avec CoolGraphics dans une classe CoolGraphicsAdapter.Canvas avec SimpleGraphics dans une classe SimpleGraphicsAdapter.
L'application Paint ne dépend que de Canvas
boolean legacy = args2.length==2 && args2[0].equals("-legacy");
Path path = Path.of(args2.length==2 ? args2[1] :args2[0]);
var drawing = Drawing.fromFile(path);
// DISPLAY
Canvas canvas;
if (legacy) {
canvas = new SimpleGraphicsAdapter("area", 500, 500);
} else {
canvas = new CoolGraphicsAdapter("area", 500, 500);
}
drawing.paintAll(canvas);
canvas.waitForMouseClick((x, y) -> drawing.onClick(canvas, x, y));
Problème: En simplifiant notre API au maximum, on a perdu la possibilité qui étaient offerte par SimpleGraphics d'afficher plusieurs dessins à la fois.
Idée: on rajouter une méthode methode render() dans l'interface Canvas avec le contrat que les affichages ne se font que lorsqu'on appel la méthode render().
Si vous êtes bloqué sur comment écrire vos adaptateurs, le slide suivant donne un peu d'aide mais essayez de le faire seul.
public class SimpleGraphicsAdapter implements CanvasOpt {
private final SimpleGraphics sg;
private final ArrayList<Consumer<Graphics2D>> drawingActions = new ArrayList<>();
@Override
public void drawLine(int x1, int y1, int x2, int y2, CanvasColor c) {
drawingActions.add(graphics2D -> {
graphics2D.setColor(toSimpleGraphicsColor(c));
graphics2D.drawLine(x1,y1,x2,y2);
});
}
@Override
public void render() {
var actionsTodo = List.copyOf(drawingActions); // thread-safety
drawingActions.clear();
sg.render(graphics2D -> {
actionsTodo.forEach(consumer -> consumer.accept(graphics2D));
});
}
Java: On peut éviter de passer par une liste avec andThen.