Refactoring JavaDraw
JPanel ohne Design Pattern -> Command Pattern
Problemstellung: Alles im JPanel
- Direkte Implementierung der Zeichenlogik in der Panel-Klasse
DrawingPanelBefore
- Lange
if
- oderswitch
-Anweisungen für Mausereignisse - Schwierige Erweiterung und Wartung
DrawingPanelBefore

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class DrawingPanelBefore extends JPanel implements MouseListener, MouseMotionListener {
private Point startPoint;
private Point endPoint;
private String currentTool = "RECTANGLE"; // Beispielwerkzeug
public DrawingPanelBefore() {
addMouseListener(this);
addMouseMotionListener(this);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (startPoint != null && endPoint != null) {
int x = Math.min(startPoint.x, endPoint.x);
int y = Math.min(startPoint.y, endPoint.y);
int width = Math.abs(startPoint.x - endPoint.x);
int height = Math.abs(startPoint.y - endPoint.y);
switch (currentTool) {
case "RECTANGLE":
g.drawRect(x, y, width, height);
break;
// Weitere Fälle für andere Werkzeuge
}
}
}
@Override
public void mousePressed(MouseEvent e) {
startPoint = e.getPoint();
}
@Override
public void mouseReleased(MouseEvent e) {
endPoint = e.getPoint();
repaint();
}
@Override
public void mouseDragged(MouseEvent e) {
endPoint = e.getPoint();
repaint();
}
// Leere Implementierungen für nicht genutzte Methoden
@Override public void mouseClicked(MouseEvent e) {}
@Override public void mouseEntered(MouseEvent e) {}
@Override public void mouseExited(MouseEvent e) {}
@Override public void mouseMoved(MouseEvent e) {}
}
Refactoring: Einführung des Command Patterns
-
Trennung von Zeichenlogik und UI-Handling
-
Jede Zeichenaktion wird durch ein Command-Objekt gekapselt
-
Einfache Hinzufügung neuer Zeichenwerkzeuge
-
DrawingPanelAfter
,interface DrawingCommand
,DrawRectangleCommand
und weitere.
nach Refactoring

public interface DrawingCommand {
void mousePressed(int x, int y);
void mouseDragged(int x, int y);
void mouseReleased(int x, int y);
void execute();
void undo();
}
public class DrawRectangleCommand implements DrawingCommand {
private Point startPoint;
private Point currentPoint;
private DrawingPanelAfter panel;
public DrawRectangleCommand(DrawingPanelAfter panel) {
this.panel = panel;
}
@Override
public void mousePressed(int x, int y) {
startPoint = new Point(x, y);
}
@Override
public void mouseDragged(int x, int y) {
currentPoint = new Point(x, y);
panel.repaint();
}
@Override
public void mouseReleased(int x, int y) {
currentPoint = new Point(x, y);
panel.addRectangle(startPoint.x, startPoint.y, Math.abs(x - startPoint.x),
Math.abs(y - startPoint.y));
panel.repaint();
}
// Vorheriger Zustand, z.B. eine Liste aller bisher gezeichneten Formen
private DrawingPanelAfter panel;
@Override
public void execute() {
// Zeichnen des Rechtecks
}
@Override
public void undo() {
// Entfernen des zuletzt gezeichneten Rechtecks
}
}
public class DrawLineCommand implements DrawingCommand {
private Point startPoint;
private Point currentPoint;
private DrawingPanelAfter panel;
public DrawLineCommand(DrawingPanelAfter panel) {
this.panel = panel;
}
@Override
public void mousePressed(int x, int y) {
startPoint = new Point(x, y);
}
@Override
public void mouseDragged(int x, int y) {
currentPoint = new Point(x, y);
panel.repaint();
}
@Override
public void mouseReleased(int x, int y) {
currentPoint = new Point(x, y);
panel.addLine(startPoint.x, startPoint.y, x, y);
panel.repaint();
}
}
import java.util.ArrayList;
public class DrawingPanelAfter extends JPanel implements MouseListener, MouseMotionListener {
private DrawingCommand currentCommand;
private ArrayList<Shape> shapes = new ArrayList<>();
public DrawingPanelAfter() {
setDrawingTool("LINE"); // Standardmäßig Linien-Werkzeug
addMouseListener(this);
addMouseMotionListener(this);
}
public void setDrawingTool(String toolType) {
switch (toolType) {
case "RECTANGLE":
this.currentCommand = new DrawRectangleCommand(this);
break;
case "LINE":
this.currentCommand = new DrawLineCommand(this);
break;
// Weitere Werkzeuge können hier hinzugefügt werden
}
}
public void addRectangle(int x, int y, int width, int height) {
shapes.add(new Rectangle(x, y, width, height));
}
public void addLine(int startX, int startY, int endX, int endY) {
shapes.add(new Line2D.Float(startX, startY, endX, endY));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (Shape shape : shapes) {
g2.draw(shape);
}
}
@Override
public void mousePressed(MouseEvent e) {
currentCommand.mousePressed(e.getX(), e.getY());
}
@Override
public void mouseReleased(MouseEvent e) {
currentCommand.mouseReleased(e.getX(), e.getY());
}
@Override
public void mouseDragged(MouseEvent e) {
currentCommand.mouseDragged(e.getX(), e.getY());
}
// Leere Implementierungen für nicht genutzte Methoden
@Override public void mouseClicked(MouseEvent e) {}
@Override public void mouseEntered(MouseEvent e) {}
@Override public void mouseExited(MouseEvent e) {}
@Override public void mouseMoved(MouseEvent e) {}
}
Command Pattern Struktur
-
Command Interface: Definiert die Aktionen
execute()
,undo()
- Konkrete Commands: Implementieren spezifische Zeichenaktionen
- Invoker: Ruft Commands basierend auf Benutzerinteraktion aus
- Client: Setzt das aktuelle Command basierend auf der UI-Auswahl

Command Pattern Struktur
Vorteile des Command Patterns
- Modularität: Jedes Command ist eine eigenständige Einheit
- Erweiterbarkeit: Neue Commands können leicht hinzugefügt werden
- Flexibilität: Änderungen an einem Command beeinflussen nicht den Rest des Systems
Zusätzlicher Vorteil: Undo/Redo Mechanismus
- Einfache Integration eines Undo/Redo-Mechanismus
- History-Manager verwaltet die Befehlshistorie
- Befehle können rückgängig gemacht oder wiederholt werden ohne die Hauptlogik zu beeinträchtigen
Implementierung des Undo/Redo Mechanismus
-
Command erweitern: Um
undo
Methode - History Manager: Verwaltet Undo/Redo Stacks
- Integration: Undo/Redo Aktionen in der UI
Fazit
- Das Command Pattern verbessert die Struktur und Wartbarkeit
- Ermöglicht einfache Erweiterungen und Anpassungen
- Der Undo/Redo-Mechanismus erhöht die Benutzerfreundlichkeit
Refactoring JavaDraw
By Harald Haberstroh
Refactoring JavaDraw
- 96