有时候,可能会遇到带有两种甚至更多种分格的实例的类,并包含标识实例分格的标签域,举个栗子
public class Figure{
enum Shape {
RECTANGLE,
CIRCLE
}
// Tag field - the shape of this figure
final Shape shape;
// These field are use only if shape if RECTANGLE
double length;
double width;
// This field is use only if shape is CIRCLE
double radius;
// Constructor for circle
public Figure(double radius) {
shape = Shape.CIRCLE;
this.radius = radius;
}
// Constructor for rectangle
public 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();
}
}
}
这样的标签类有许多缺点,充斥着样板代码,包括枚举,标签域以及条件语句。由于多个乱七八糟的实现挤在了一个类中,破坏了可读性。一句话总结标签类过于冗长,容易出错,并且效率低下。
好的处理方法——子类化类型
为了将标签类转化成类层次,首先要为标签类中的每个方法都定义一个包含抽象方法的抽象类。在上述类中只有一个这样的方法area。这个抽象类是类层次的根,看代码
abstract class Figure {
abstract double area();
}
class Circle extends Figure {
final double radius;
Circle(double radius) {
this.radius = radius;
}
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;
}
double area() {
return length * width;
}
}
简而言之,标签类很少有使用的时候。当你想编写一个包含显示标签域的类时,应该考虑一下,这个标签是否可以被取消,这个类是否可以用层次类来代替。当你遇到一个现有的包含标签域的类时,你应该考虑把它重构到一个层次结构中去