Lets you add new operations to existing classes without modifying them.
Separates an algorithm from the objects it operates on.
abstract class Shape {
void accept(ShapeVisitor visitor);
}
class Circle implements Shape {
final double radius;
Circle(this.radius);
@override
void accept(ShapeVisitor visitor) => visitor.visitCircle(this);
}
class Square implements Shape {
final double side;
Square(this.side);
@override
void accept(ShapeVisitor visitor) => visitor.visitSquare(this);
}
abstract class ShapeVisitor {
void visitCircle(Circle c);
void visitSquare(Square s);
}
class AreaCalculator implements ShapeVisitor {
@override
void visitCircle(Circle c) => print('Circle area: ${3.14 * c.radius * c.radius}');
@override
void visitSquare(Square s) => print('Square area: ${s.side * s.side}');
}
// Usage
final shapes = [Circle(5), Square(4)];
final calc = AreaCalculator();
for (final s in shapes) {
s.accept(calc);
}
// Circle area: 78.5
// Square area: 16.0