有时候,可能会遇到带有两种甚至更多种风格的实例的类,并包含表示实例风格的标签(tag)域。例如,考虑下面这个类,它能够表示圆形或者矩形:
//Tagged class - vastly inferior to a class hierarchy 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(); } } }
这种标签类(tagged class)有着许多的缺点。
- 破坏可读性
- 内存消耗
- 域不能做成final的
一句话:标签类过于冗长、容易出错、并且效率低下。
幸运的是,面向对象语言例如Java,就提供了其他更好的方法定义能表示多种风格对象的单个数据类型:子类型化(subtyping)。标签类正是类层次的一种简单的仿效。简而言之,标签类很少有适用的时候。当你想编写一个包含显式标签域的类时,应该考虑一下,这个标签是否可以被取消,这个类是否可以用类层次来代替。当你遇到一个包含标签域的现有类时,就要考虑将它重构到一个类层次结构中去。//Class hierarchy replacement for a tagged class abstract class Figure1 { abstract double area(); class Circle extends Figure1 { final double radius; Circle(double radius) { this.radius = radius; } @Override double area() { return Math.PI * (radius * radius); } } class Rectangle extends Figure1 { final double length; final double width; Rectangle(double length, double width) { this.length = length; this.width = width; } @Override double area() { return width * length; } } }
Effective Java 第 20 条: 类层次优于标签类
最新推荐文章于 2021-02-12 22:17:38 发布