Java 杂谈

Effective-java 3 中文翻译系列 (Item 23

2018-07-25  本文已影响25人  TryEnough

文章也上传到

github

(欢迎关注,欢迎大神提点。)


ITEM 23 优先使用类层级结构,减少使用tag标记类


有时候一个类对象可以表示多种形式,用一个tag值指示这个类对象表示哪一种形式。例如下面表示圆形和矩形的类:

    class Figure {
        enum Shape { RECTANGLE, CIRCLE };
        // Tag field - the shape of this figure
        final Shape shape;
        // These fields are used only if shape is RECTANGLE
        double length;
        double width;
        // This field is used only if shape is CIRCLE
        double radius;
        // Constructor for circle
        Figure(double radius) {
            shape = Shape.CIRCLE;
            this.radius = radius;
        }
        // Constructor for rectangle
        Figure(double length, double width) {
            shape = Shape.RECTANGLE;
            this.length = length;
            this.width = width;
        }
        double area() {
            switch(shape) {
                case RECTANGLE:
                    return length * width;
                case CIRCLE:
                    return Math.PI * (radius * radius);
                default:
                    throw new AssertionError(shape);
            }
        }
    }

像这样一个tag类有很多的缺点:

幸运的是,像Java一样的面向对象语言提供了一种更好的可以代表多种形态的替代方案:子类类型。而tag类其实就是模仿子类的一种简单的实现而已。

转换tag类成为继承结构;

    abstract class Figure {
        abstract double area();
    }
    
    class Circle extends Figure {
        final double radius;
        Circle(double radius) { this.radius = radius; }
        @Override double area() { return Math.PI * (radius * radius); }
    }
    
    class Rectangle extends Figure {
        final double length;
        final double width;
        Rectangle(double length, double width) {
            this.length = length;
            this.width = width;
        }
        @Override double area() { return length * width; }
    }

这个类层次修复了刚才提到的所有tag类的缺点。

类层级带来的其他的优点是,很自然的映射出了类层次的关系,提供了更灵活也更好的编译期检查。这个类层级很容易可以被扩展,例如添加正方形:

class Square extends Rectangle {
    Square(double side) {
    super(side, side);
    }
}

注意,上面例子为了简洁,把数据属性设置成可以直接访问的,而不是通过存取器。真实场景下使用时应该注意public属性的缺陷(Item16)。

总结:tag类总是不太恰当的,如果你打算写一个类用tag来区分不同行为,考虑将其替换成类层级关系。

上一篇下一篇

猜你喜欢

热点阅读