import java.util.LinkedList; interface Shape { public String draw(); } class RectangleTest { public static void main(String[] args) { Canvas c = new Canvas(); Point p1 = new Point(new Number(1), new Number(2)); Point p2 = new Point(new Number(60), new Number(20)); Rectangle r1 = new Rectangle(p1, p2); c.addShape(r1); Point p3 = new ColoredPoint(new RationalNumber(1, 2), new RationalNumber(60, 2), Color.purple); Point p4 = new ColoredPoint(new RationalNumber(150, 3), new RationalNumber(333, 7), Color.purple); Rectangle r2 = new Rectangle(p3, p4); c.addShape(r2); System.out.println(c.draw()); } } class Canvas implements Shape { LinkedList shapes = new LinkedList(); public void addShape(Shape sh) { shapes.add(sh); } public String draw() { String s = ""; for (Shape sh : shapes) { s += sh.draw(); } s += ""; return s; } } class Rectangle implements Shape { protected Point topLeft; protected Point bottomRight; public Rectangle(Point topLeft, Point bottomRight) { this.topLeft = topLeft; this.bottomRight = bottomRight; } public String toString() { return "[" + topLeft.toString() + "," + bottomRight.toString() + "]"; } public String draw() { String s = ""; for (Number x = topLeft.x; x.lessThan(bottomRight.x); x = x.plus(Number.One)) { for (Number y = topLeft.y; y.lessThan(bottomRight.y); y = y.plus(Number.One)) { Point p = topLeft.copyWith(x, y); s += p.draw(); } } return s; } } class Point implements Shape { protected Number x; protected Number y; public Point(Number x, Number y) { this.x = x; this.y = y; } public String toString() { return "(" + x.toString() + "," + y.toString() + ")"; } public String draw() { return ""; } public Point copyWith(Number x, Number y) { return new Point(x, y); } } class Number { protected double value; public static Number One = new Number(1); public Number(double value) { this.value = value; } public Number plus(Number other) { return new Number(value + other.value); } public boolean lessThan(Number other) { return value < other.value; } public String toString() { return String.valueOf(value); } } /* Observe that I can EXTEND my program by only APPENDING a new * class for RationalNumber, and then modifying just the main * method. I do not need to modify any prior code, including * either Point or Rectangle. They just work! Asymptotically, * instead of having to modify O(m*n) things when adding n new * things to a language, I only need to modify O(n). */ class RationalNumber extends Number { protected double numerator; protected double denominator; public RationalNumber(double numerator, double denominator) { super(numerator / denominator); this.numerator = numerator; this.denominator = denominator; } public RationalNumber plus(RationalNumber other) { // ensure both numbers have the same denominator double num1 = numerator * other.denominator; double num2 = other.numerator * denominator; double den = denominator * other.denominator; return new RationalNumber(num1 + num2, den); } public String toString() { // return String.valueOf(numerator) + "/" + String.valueOf(denominator); return String.valueOf(numerator / denominator); } } enum Color { red, green, blue, purple } class ColoredPoint extends Point { Color c; public ColoredPoint(Number x, Number y, Color c) { super(x, y); this.c = c; } public String draw() { return ""; } public Point copyWith(Number x, Number y) { return new ColoredPoint(x, y, c); } }