EffectiveJava——类层次优于标签类

标签类:

有时候,可能会遇到带有两种甚至更多钟风格的类的实例的类,并包含表示实例风格的(tag)域。例如下面这个类,它能够表示圆形或者矩形:

/**
 * 类层次优先与标签类
 * @author weishiyao
 *
 */
// Tagged class - vastly inferior to a class hierarchy
public class Figure1{
	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 Figure1(double radius) {
		shape = Shape.CIRCLE;
		this.radius = radius;
	}

	// Constructor for rectangle
	public Figure1(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();
		}
	}
}

  这种标签类有着许多缺点:

1.它们中充斥着样板代码,包括枚举声明,标签域以及条件语句。由于许多个实现乱七八糟的挤在了单个类中,破坏了可读性。

2.内存占用也增加了,因为实例承担了属于其他风格的不相关的域。

3.域也不能做成final类型的,除非构造器初始化了不相关的域,产生了更多的样板代码。构造器必须不借助编译器,来设置标签域,并且初始化正确的数据域;如果初始化了错误的域,程序就会在运行的时候出错。

4.无法给标签类添加风格,除非可以修改源文件,如果一定要添加风格,就必须给每个条件语句都添加一个条件,否则就会在运行的时候失败。

5.最后,实例的数据类型没有提供任何关于其风格的线索

总结:标签类过于冗长、容易出错,并且效率低下

  幸运的是,面向对象的语言java,提供了其他更好的方法来定义能表示多种风格对象的单个数据类型:子类型化。标签类正是类层次的一种简单效仿。

  为了将标签类转化成类层次,首先要为标签类中的每一个方法都定义一个包含抽象方法的抽象类,这每个方法的行为都依赖于标签值。在Figure类中,只有一个这样的方法:area。这个抽象类是类层次的根。如果还有其他的方法行为不依赖于某个标签的值,就把这样的方法放到这个类中。同样的,如果所有的方法都用到了某些数据域,就应该把他们放在这个类中。在Figure类中,不存在这种类型独立的方法或者数据域。

/**
 * 类层次优于标签类
 * @author weishiyao
 *
 */
// Class hierarchy replacement for a tagged class
abstract class Figure2 {
	abstract double area();
}

class Circle extends Figure2 {
	final double radius;

	Circle(double radius) {
		this.radius = radius;
	}

	double area() {
		return Math.PI * (radius * radius);
	}
}

class Rectangle extends Figure2 {
	final double length;
	final double width;

	Rectangle(double length, double width) {
		this.length = length;
		this.width = width;
	}
	double area() {
		return length * width;
	}
}

  这个类纠正了前面提到过的标签类的所有缺点。这段代码简单且清楚,没有包含在原来版本中所见到的所有样板代码。每个类型都有自己的类,这些类都没有受到不相关的数据域的拖累。所有的域都是final的。编译器确保每个类的构造器都初始化它的数据域,对于根类中声明的每个抽象方法,都确保有一个实现。这样就杜绝了由于遗漏switch case而导致运行失败的可能性。多个程序员都可以独立的扩展层次结构,并且不用访问根类的资源代码就能互相操作。每种类型都有一种相关的独立的数据类型,允许程序员指明变量类型,限制变量,并将参数输入到特殊的类型。

  类层次的另一个好处在于,它们可以用来反应类型之间本质上的层次关系,有助于增强灵活性,并更好的进行编译时类型检查。

  总而言之,标签类很少有适用的时候。当你想要编写一个包含显示的标签域的类时,应该考虑一下,这个标签是否可以被取消,这个类是否可以用类层次来代替,当你遇到一个包含标签域的现有类时,就要考虑将它重构到一个层次结构中去。

时间: 2024-12-08 13:08:06

EffectiveJava——类层次优于标签类的相关文章

Effective Java 第三版——23. 优先使用类层次而不是标签类

Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将近8年的时间,但随着Java 6,7,8,甚至9的发布,Java语言发生了深刻的变化. 在这里第一时间翻译成中文版.供大家学习分享之用. 23. 优先使用类层次而不是标签类 有时你可能会碰到一个类,它的实例有两个或更多的风格,并且包含一个标签属性(tag field),表示实例的风格. 例如,考虑这个类,它可

三点新的体会:多实践,新技术人人平等,项目类层次划分和管理

最近一段时间,通过自己做项目,以及同一位小朋友的交流,有一些新的体会: 第一,要多实践.看书呢有2个左右,第一是可以入门.第二是往深了学,很多知识和api难以自己探索到,毕竟不是自己发明的语言和平台,得学别人已经提供的平台和知识.但是光看书也不行,主要有以下缺陷:1)没有像样的东西拿出来既无法说服人,自己也心虚.2)也拿不出自己的核心产品来挣钱3)在实际开发中同样会遇到很多问题,第一手的开发心得不是书上能教你的,别人的心得告诉你你也不懂,所谓懂了也是半懂不懂.再比如书上说如何定义类,如何实例化,

Java输入、输入、IO流 类层次关系梳理

Java输入.输入.IO流 类层次关系梳理 本文主要关注在Java编程中涉及到的IO相关的类库.方法.以及对各个层次(抽线.接口继承)的流之间的关系进行梳理 相关学习资料 http://baike.baidu.com/view/1007958.htm?noadapt=1 http://blog.csdn.net/hguisu/article/details/7418161 https://www.ibm.com/developerworks/cn/java/j-lo-javaio/ http:/

同一Page范围内多个相同自定义标签类实例化个数相关问题阐述

问题描述:(jsp自定义标签代码片段中出现出来多个相同类型的标签<JB:ToobarCellComponent.那么jsp引擎是否实例化多个标签对象呢)那么大家可能就奇怪了,研究这个问题到底对我们项目研发有何好处呢?其实这个问题可以延伸出很多关于java自定义标签的一些高级应用以及自定义标签的解析原理,比如自定义标签按钮级别的权限控制[页面控件权值记录,初始化等]等.研究这些设计框架大有所益处,以下内容但愿对你有所帮助.也欢迎大家进入群[376447127]与我交流RAD快速开发平台相关技术.

Cocos2d-x 3.0标签类Label

Cocos2d-x 3.0后推出了新的标签类Label,这种标签通过使用FreeType[1]来使它在不同的平台上有相同的视觉效果.由于使用更快的缓存代理,它的渲染也将更加快速.Label提供了描边和阴影等特性. Label类的类图如下图所示: 创建Label类静态create函数常用的有如下几个: [html] view plaincopy static Label* createWithSystemFont(conststd::string &text,             //是要显示

Java类载入器(一)——类载入器层次与模型

类载入器 ??虚拟机设计团队把类载入阶段中的"通过一个类的全限定名来获取描写叙述此类的二进制字节流"这个动作放到Java虚拟机外部去实现.以便让应用程序自己决定怎样去获取所须要的类.实现这个动作的代码模块称为"类载入器". 类载入器层次(等级) ??从JVM的角度来讲,仅仅存在两种不同的类载入器. ??第一类是启动类载入器(Bootstrap ClassLoader):这个类载入器主要载入JVM自身工作须要的类.这个类载入器由C++语言实现(特指HotSpot).是

JavaEE自定义标签:标签类的创建、tld配置文件的创建(位置、如何创建)、Web-XML配置、JSP应用

1.标签 以类似于html标签的方式实现的java代码的封装. 第一:形成了开发标签的技术标准---自定义标签的技术标准. 第二:java标准标签库(sun之前自己开发的一系列的标签的集合)jstl,以及表达式语言EL. 2.自定义标签 (1)理解: 可以允许用户自己根据自己的需要,去开发自己的标签的技术规范. 通俗:在Jsp页面上,以简单的标签封装java代码的操作. //在自定义标签类中,先调用setPageContext()实例化内置对象: //然后是doStartTag()方法,核心代码

教程1-UILabel标签类的使用

UILabel标签类的使用 知识点大纲 1. 什么是标签? 2. 标签的基本使用 3. 标签的常用属性 知识点详解 1. 什么是标签? 如下如所示, 我们很多时候需要在界面上显示文本数据, iOS为我们提供了UILabel标签类, 我们可以使用这个类在我们的界面上显示文本数据 2. 标签的基本使用 //实例: 屏幕的上方显示一个文本 Helloworld //1.创建UILabel的对象,可以使用这个label显示文本 UILabel *label = [[UILabel alloc] init

Effective Java 第三版——42.lambda表达式优于匿名类

Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将近8年的时间,但随着Java 6,7,8,甚至9的发布,Java语言发生了深刻的变化. 在这里第一时间翻译成中文版.供大家学习分享之用. 42.lambda表达式优于匿名类 在Java 8中,添加了函数式接口,lambda表达式和方法引用,以便更容易地创建函数对象. Stream API随着其他语言的修改一同