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而导致运行失败的可能性。多个程序员都可以独立的扩展层次结构,并且不用访问根类的资源代码就能互相操作。每种类型都有一种相关的独立的数据类型,允许程序员指明变量类型,限制变量,并将参数输入到特殊的类型。
类层次的另一个好处在于,它们可以用来反应类型之间本质上的层次关系,有助于增强灵活性,并更好的进行编译时类型检查。
总而言之,标签类很少有适用的时候。当你想要编写一个包含显示的标签域的类时,应该考虑一下,这个标签是否可以被取消,这个类是否可以用类层次来代替,当你遇到一个包含标签域的现有类时,就要考虑将它重构到一个层次结构中去。
EffectiveJava——类层次优于标签类的更多相关文章
- Effective Java 第三版——23. 优先使用类层次而不是标签类
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- EffectiveJava(20)使用子类型化优化标签类
标签类:其中有许多样板代码,包括枚举声明,标签域和条件语句 如果要给它添加风格,除了有权限修改源码之外,你还得给每个条件语句都添加一个条件,否则就会在运行时失败 标签类过于冗长,容易出错,并且效率低下 ...
- Java集合框架的接口和类层次关系结构图
Collection和Collections的区别 首先要说的是,"Collection" 和 "Collections"是两个不同的概念: 如下图所示,&qu ...
- Java输入、输入、IO流 类层次关系梳理
本文主要关注在Java编程中涉及到的IO相关的类库.方法.以及对各个层次(抽线.接口继承)的流之间的关系进行梳理 相关学习资料 http://baike.baidu.com/view/1007958. ...
- Cocos2d-x 3.0标签类Label
Cocos2d-x 3.0后推出了新的标签类Label,这种标签通过使用FreeType[1]来使它在不同的平台上有相同的视觉效果.由于使用更快的缓存代理,它的渲染也将更加快速.Label提供了描边和 ...
- JavaEE自定义标签:标签类的创建、tld配置文件的创建(位置、如何创建)、Web-XML配置、JSP应用
1.标签 以类似于html标签的方式实现的java代码的封装. 第一:形成了开发标签的技术标准---自定义标签的技术标准. 第二:java标准标签库(sun之前自己开发的一系列的标签的集合)jstl, ...
- c++ 容器、继承层次、句柄类
一.容器与继承 在容器中保存有继承关系的对象,如果定义成保存基类对象,则派生类将被切割,如果定义成保存派生类对象,则保存基类对象又成问题(基类对象将被强制转换成派生类对象,而派生类中定义的成员未被初始 ...
- Effective Java 第三版——42.lambda表达式优于匿名类
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- 高并发分布式系统中生成全局唯一(订单号)Id js返回上一页并刷新、返回上一页、自动刷新页面 父页面操作嵌套iframe子页面的HTML标签元素 .net判断System.Data.DataRow中是否包含某列 .Net使用system.Security.Cryptography.RNGCryptoServiceProvider类与System.Random类生成随机数
高并发分布式系统中生成全局唯一(订单号)Id 1.GUID数据因毫无规律可言造成索引效率低下,影响了系统的性能,那么通过组合的方式,保留GUID的10个字节,用另6个字节表示GUID生成的时间(D ...
随机推荐
- [原]OpenGL基础教程(五)缓冲区数据更新方式
1.glBufferSubData 适用于相同数据类型 void SetPositionY(float y){ vector<Vector3<float>>::itera ...
- Spark源码系列(九)Spark SQL初体验之解析过程详解
好久没更新博客了,之前学了一些R语言和机器学习的内容,做了一些笔记,之后也会放到博客上面来给大家共享.一个月前就打算更新Spark Sql的内容了,因为一些别的事情耽误了,今天就简单写点,Spark1 ...
- BATCH(BAT批处理命令语法)
bat语法备忘扩展名是bat(在nt/2000/xp/2003下也可以是cmd)的文件就是批处理文件[@more@] bat语法备忘扩展名是bat(在nt/2000/xp/2003下也可以是cmd)的 ...
- .woff HTTP GET 404 (Not Found)
原因:IIS没有添加woff字体的MIME类型,导致HTTP请求404 Not Found错误 解决办法: 1.在web.config中配置 <system.webServer> < ...
- 二十五、【开源】EFW框架Winform前端开发之强大的自定义控件库
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.2:http://pan.baidu.com/s/1hcnuA EFW框架实例源代码下载:http://pan ...
- coreseek 提示 client version is higher than daemon version 解决办法
安装好coreseek,开启了服务之后,通过 sphinx php扩展去请求数据,提示:client version is higher than daemon version (client is ...
- Python Django 开发 2 数据库
一半教程用的Django都是1.8以前的版本,导致跟我用的1.8.2的版本用法有些出入,所以只能自己去官网看文档,以下一下是看官方文档而理解的,英语渣渣,可能会有理解有误的地方 先记录下如何查看dja ...
- 【原创】MYSQL++源码剖析——前言与目录
终于完成了! 从第一次想写到现在真的写好大概花了我3个月时间.原来一直读人家的系列文章,总感慨作者的用心良苦和无私奉献,自己在心里总是会觉得有那么些冲动也来写一个. 最开始的麻烦是犹豫该选哪个主题.其 ...
- Java知多少(109)数据库更新
数据库更新操作包括数据表创建.删除.以及数据表记录的增加.删除.修改等操作.如果利用数据 SQL命令实现,则利用Statement对旬的executeUpdate()方法,执行SQL的update语句 ...
- 疯狂的ASP.NET系列-第一篇:啥是ASP.NET
最近想学下ASP.NET,于是在网店上看到一本书叫做ASP.NET高级程序设计,老婆在旁边问了句:“这个不是DSP(数字信号处理,大学读的电子,所以这个比较熟),是ASP啊,什么是ASP啊?”.我想了 ...