Clean Data Objects and Classes!

Notes from Clean Code - Chapter 4!
  • Hiding implementation is not just putting a layer of functions!
  • Hiding implementation is about abstractions!
  • Express data in abstract terms!
  • Worst thing to do is to blindly adding getters / setters!
Mature programmers know that the idea that everything is an object is a myth! Sometimes you really do want simple data structures with procedures operating on them.
The above statement is backed up by the following example..
package biz.tugay;
 
public class Circle {
 
    public final double radius;
 
    public Circle(double radius) {
        this.radius = radius;
    }
}
 
package biz.tugay;
 
public class Rectangle {
 
    public final double height;
    public final double width;
 
    public Rectangle(double height, double width) {
        this.height = height;
        this.width = width;
    }
}
 
package biz.tugay;
 
public class Square {
 
    public final double side;
 
    public Square(double side) {
        this.side = side;
    }
}
 
package biz.tugay;
 
public class Geometry {
 
    public double area(Object shape) {
        if (shape instanceof Circle) {
            final Circle circle = (Circle) shape;
            return Math.PI * circle.radius * circle.radius;
        }
        if (shape instanceof Rectangle) {
            final Rectangle rectangle = (Rectangle) shape;
            return rectangle.height * rectangle.width;
        }
        if (shape instanceof Square) {
            final Square square = (Square) shape;
            return square.side * square.side;
        }
        throw new UnsupportedOperationException("Make sure you pass a Shape!");
    }
}
and it is justified by the following explanation..
Consider what would happen if a perimeter() function were added to Geometry. The shape classes would be unaffected! Any other classes that depended upon the shapes would also be unaffected! On the other hand, if I add a new shape, I must change all the functions in Geometry to deal with it.
Procedural code (code using data structures, as the example above) makes it easy to add new functions without changing the existing data structures. Object Oriented code, on the other hand, makes it easy to add new classes without changing existing functions.
I am not sure, as usual, about this. I think adding methods to every class is still better than adding one new giant function with several if statements with instance of operator!

I think the following is always better..
package biz.tugay;
 
public interface Planar {
    double area();
}
 
package biz.tugay;
 
public class Circle implements Planar {
 
    private final double radius;
 
    public Circle(double radius) {
        this.radius = radius;
    }
 
    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}
 
package biz.tugay;
 
public class Rectangle implements Planar {
 
    private final double height;
    private final double width;
 
    public Rectangle(double height, double width) {
        this.height = height;
        this.width = width;
    }
 
    @Override
    public double area() {
        return height * width;
    }
}
 
package biz.tugay;
 
public class Square implements Planar {
 
    public final double side;
 
    public Square(double side) {
        this.side = side;
    }
 
    @Override
    public double area() {
        return side * side;
    }
}