Effective Java 第 20 条: 类层次优于标签类

有时候,可能会遇到带有两种甚至更多种风格的实例的类,并包含表示实例风格的标签(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 条: 类层次优于标签类)