POO & Design Patterns

Indications TD2

Exercice 1 - TD2

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.

Exercice 1 - TD2

    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);
    }

}

Exercice 1 - TD2

Il y a plusieurs questions auxquelles il faut savoir répondre:

  • Pourquoi ne pas prendre l'énumération Color de CoolGraphics ?
  • Pareil pour l'interface fonctionnelle ?
  • Pour ne pas avoir utilisé BiConsumer<Interger,Integer> à la place de définir une interface fonctionnelle ?
  • Pourquoi drawRectangle est en default.

Exercice 1 - TD2

  • On implément l'interface Canvas avec CoolGraphics dans une classe CoolGraphicsAdapter.
  • On implément l'interface Canvas avec SimpleGraphics dans une classe SimpleGraphicsAdapter.

Exercice 1 - TD2

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));    

Exercice 2 - TD2

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.

Exercice 2 - TD2

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.