Effective Java笔记(23)类层次优于标签类

《Effective Java》第23条:类层次优于标签类 每种类型都有一种相关的独立的数据类型,允许程序员指明变量的类型,限制变量,并将参数输入到特殊的类型。先来认识一下什么叫标签类:它是一种设计模式,指一个类通过一个 “标签” 字段(如枚举、整数等)来区分不同的状态或类型,并根据标签的不同执行不同的逻辑。5、不灵活:要添加一种新类型,必须修改这个核心类的源代码,并排查所有条件语句进行更新,违反了“对扩展开放,对修改关闭”的原则。标签类正是对类层次的一种简单的仿效。总之:标签类的适用场景非常的少,当你想要实现一个标签类时,要考虑将它重构到一个层次结构中去。 阅读详情

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

class Figure{
    enum Shape { RECTANGLE, CIRCLE };
    final Shape shape;
    double length;
    double width;
    double radius;
    Figure(double radius) {
        shape = Shape.CIRCLE;
        this.radius = radius;
    }
    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(shape);
        }
    }
}

        这种标签类( tagged class ) 有许多缺点 。 它们中充斥着样板代码,包括枚举声明、标签域以及条件语句 。 由于多个实现乱七八糟地挤在单个类中,破坏了可读性 。 由于实例承担着属于其他风格的不相关的域 ,因此内存占用也增加了 。 域不能做成 final 的, 除非构造器初始化了不相关的域,产生了更多的样板代码 。 构造器必须不借助编译器来设置标签域,并初始化正确的数据域 : 如果初始化了错误的域, 程序就会在运行时失败 。 无法给标签类添加风格,除非可以修改它的源文件 。 如果一定要添加风格 , 就必须记得给每个条件语句都添加一个条件,否则类就会在运行时失败 。 最后 , 实例的数据类型没有提供任何关于其风格的线索 。 一句话, 标签类过于冗长、容易出错,并且效率低下 。

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

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

        接下来,为每种原始标签类都定义根类的具体子类 。 在前面的例子中,这样的类型有两个:圆形( circle )和矩形( rectangle ) 。 在每个子类中都包含特定于该类型 的数据域 。 在我们的示例中,radius 是特定于圆形的,length 和 width 是特定于矩形的 。同时在每个子类中还包括针对根类中每个抽象方法的相应实现 。以下是与原始的 Figure 类相对应的类层次:

abstract class Figure {
    abstract double area();
}
class Circle extends Figure {
    final double radius;
    Circle(double radius) { this.radius = radius; }
    @Override 
    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;
    }
    @Override 
    double area() { return length * width; }
}

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

        类层次的另一个好处在于 ,它们可以用来反映类型之间本质上的层次关系,有助于增强灵活性,并有助于更好地进行编译时类型检查 。 假设上述例子中的标签类也允许表达正方形 。 类层次可以反映出正方形是一种特殊的矩形这一事实(假设两者都是不可变的):

class Square extends Rectangle {
    Square(double side) {
        super(side,side);
    }
}

        注意,上述层次中的域被直接访问 ,而不是通过访问方法访问 。 这是为了简洁起见,如果层次结构是公有的,则不允许这样做 。

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

【nerfStudio】1-在windows上安装nerfStudio 安装Git。安装Visual Studio 2022。在安装CUDA之前必须完成此步骤。必须在“桌面开发与C++”工作流程(在BuildTools版本中称为“C++构建工具”)中包含所需的组件。Nerfstudio要求。我们建议使用conda来管理依赖关系。在继续之前,请确保安装了Conda。 依赖关系 PyTorch 请注意,如果安装了低于2.0.1的PyTorch版本,则应卸载先前版本的pytorch、functorch和tiny-cuda-nn。 基于CUDA 11.8的Torch 2.0.1 安装基 阅读详情

相关推荐

从SIGGRAPH审稿人视角看:什么样的TOG论文更容易被接收?

本文从SIGGRAPH审稿人视角深入解析TOG论文的审稿标准与投稿策略,揭示如何提升论文接收概率。重点探讨创新性、技术深度、实验验证等核心评分维度,并提供写作技巧与审稿意见应对策略,帮助研究者优化ACM Transactions on Graphics投稿质量。

weixin_33721344的博客 108

《Effective Java》解读第23条:类层次优于标签类

本文阐述了标签类的弊端及重构为类层次的方法。标签类通过枚举字段区分类型,导致代码臃肿、内存浪费且违反设计原则。重构步骤包括:抽取抽象根类、创建具体子类、迁移字段方法、用多态替代条件判断。类层次结构具有类型安全、易扩展等优势,符合单一职责和开闭原则。通过几何形状示例展示了标签类与层次类的差异,强调类层次是更优的面向对象设计选择。

Cosmoshhhyyy的博客 432

ABAQUS二次开发中创建SET

在ABAQUS中创建加载、边界条件时,需要使用set,创建set时需要使用对象集合对象中的Set函数,这个函数需要提供加入对象集合的列表,但这个对象列表好像并不能自行创建,只能通过ABAQUS各类对象集合中的findAt、getSequenceFromMask、getByBoundingSphere、getByBoundingCylinder或getByBoundingSphere函数得到,但这几个函数在直接使用PYTHON编程时都不太好用。这个函数返回一个字典,如下所示。

hohoyu的专栏 2482

Java:Effective java学习笔记之 接口只用于定义类型、类层次优于标签类

Java接口只用于定义类型1、 接口只用于定义类型1.1、常量接口2、 类层次优于标签类 1、 接口只用于定义类型 当类实现接口时,接口就充当可以引用这个类的实例的类型。因此,类实现了接口,就表明可以对这个类的实例实施某些动作。那么,不是为了这个目的而定义接口就是不恰当的 1.1、常量接口 有一种接口被称为常量接口,它不满足上述条件,这种接口没有包含任何方法,它只包含静态的final域,每个域都导出一个常量。 public interface PhysicalConstants { static f

JMW1407的博客 715

Ubuntu 解决WPS缺少宋体,微软雅黑等中文字体

这篇博客解决Ubuntu 18.04 无法使用中文字体的问题 问题描述

分享日常的学习,开展的项目,编写的软件,解决的问题等~ 1万+

「API取数」FDL获取金蝶云星空的单据数据

本文介绍了如何使用FDL实现金蝶云API取数以及如何有效应对复杂的API数据处理场景。

oOBubbleX的博客 2029

Effective Java~23. 类层次优于标签类

标签类,包含一个标签属性(tag field),表示实例的风格 // 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

小强快跑~~ 639

Allegro孔和线被做到器件里面如何解锁操作指导

在做PCB设计的时候,会遇到孔和线被做到器件的情况,当需要移动器件的时候,孔和线也会跟着移动。孔和线被做到器件里面如何解锁操作指导。

weixin_54787054的博客 1144

Effective Java(第三版) 学习笔记 - 第四章 类和接口 Rule20~Rule25

Effective Java(第三版) 学习笔记 - 第四章 类和接口 Rule20~Rule25 本文主要介绍了类和接口相关的内容

weixin_44453385的博客 883

基于STM32、HAL库的IP2736U_EF快充协议芯片简介及驱动程序设计

@param connected: 连接状态指针 (1=已连接, 0=未连接)= 0x2736) // 检查厂商ID。* @param hip: IP2736U句柄指针。* @param hip: IP2736U句柄指针。* @param hip: IP2736U句柄指针。* @param hip: IP2736U句柄指针。* @param hip: IP2736U句柄指针。* @param hip: IP2736U句柄指针。* @param hip: IP2736U句柄指针。

corlin6688的博客 430

【HOJ系列】HOJ判题机部署

【HOJ系列】HOJ判题机部署

随风浪仔的专栏 904

【读书笔记】Effective Java(类和接口)

读书笔记-Effective Java(类和接口)

我的博客 392

YOLOv11涨点改进 | 全网创新首发、主干改进篇 | CVPR 2025 | RAVLT主干让 YOLOv11 更加强大!通过增强线性注意力机制,特别在小目标和复杂背景的检测上表现突出

本文提出RAVLT主干网络,通过改进YOLOv11的空间特征建模能力,显著提升小物体和复杂背景检测性能。RAVLT采用秩增强线性注意力(RALA)机制,在保持线性计算复杂度的同时解决传统线性注意力低秩问题。RALA通过增强KV缓冲区和输出特征矩阵的秩,提高特征多样性和建模能力。实验表明,RAVLT在ImageNet-1k上达到84.4% Top-1准确率,仅需2600万参数和4.6GFLOPs,性能优于现有线性注意力模型。文章详细介绍了RAVLT模块结构、实现原理及在YOLOv11中的集成方法,包含四种主干

Ai缝合怪、助力小伙伴高效发论文 637

Effective Java2读书笔记-类和接口(四)

第19条:接口只用于定义类型   这一条就举了一个反例,说有些接口中只包含常量。这是对接口的不良使用。要实现相同的功能,应该使用不可实例化的工具类(第4条说过)。 public class PhysicalConstants { private PhysicalConstants() { } // Prevents instantiation /...

170

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Effective Java 3rd 条目23 类层级优于标签类

偶尔,你可能遇见一个类,它的实例有两个或者更多的特点(flavor),而且包含了一个标签(tag)域表明这个实例的特点。比如,考虑如下类,它可以代表一个圆形或者长方形:// 标签类 - 大大次于类层级! class Figure { enum Shape { RECTANGLE, CIRCLE }; // 标签域 - 这个图形的形状 final Shape shape; /

tigershin的专栏 303

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Effective Java 第三版 中文翻译

effective-java-third-edition 介绍 Effective Java 第三版全文翻译,纯属个人业余翻译,不合理的地方,望指正,感激不尽! 目录 推荐序 前言 致谢 第一章 引言 第二章 创建和销毁对象   本章涉及创建和销毁对象,包括何时以及如何创建它们,何时以及如何避免创建它们,如何确保它们被及时销毁,以及如何管理在销毁之前必须进行的清理操作。 第1项:考虑静态工...

Coloured_Glaze的博客 3861

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

《Effective Java》类和接口

第15条:使类和成员的可访问性最小化 参考学习:effective java(13) 之使类和成员的可访问性最小化 第16条:要在公有类而非公有域中使用访问方法 参考学习:effective java(14) 之在公有类中使用访问方法而非公有域 第17条:使可变性最小化 参考学习:effective java(15) 之使可变性最小化 第18条:复合优先于继承 参考学习:effective java(16) 之复合优先于继承 第19条:要么设计继承并提供文档说明,要么禁止继承 参考学习:effective

朱嫑膘的博客 253

Effective Java 学习总结

Effective Java 作为 Java 四大名著之一,聚焦于 Java 语言习惯和高效的用法。EJ 告诉读者如何更好地构建代码,以便代码能够更好地工作;也便于其他人能够理解这些代码,便于修改和改善;程序也会因此变得更加令人愉快,更加优雅。全书共90条,接下来笔者将逐条进行总结。不应该使用常量接口。一个类在内部使用某些常量是实现细节,常量接口会把这样的实现细节泄露到该类的导出 API 中标记接口:不包含方法声明的接口,它只是指明一个类实现了某种属性的接口。

Alioth4J的博客 2255

Effective Java技术要点解析

Java编程最佳实践:接口与类的设计原则 接口设计要点 接口核心原则:仅用于定义类型,避免作为常量容器 常量接口缺陷:导致API污染、兼容性问题和命名冲突 正确导出常量方式:内嵌关联类、枚举类型或不可实例化工具类 类层次结构优势 标签类问题:结构混乱、内存浪费、扩展困难 重构方法:建立抽象根类,派生具体子类 改进效果:提升类型安全、代码清晰度和内存效率 嵌套类选择策略 静态成员类:适用于公共辅助类和组件封装 非静态成员类:适配器模式和集合视图实现 选择依据:考虑访问需求、内存开销和隔离性 这些实践有助于构建

静水深流 147

Effective Java 读书笔记

读书笔记

white_while的博客 1648

Effective Java 高效编码阅读 笔记

函数参数可以传入类似listener的对象,目的是使用listener中的方法。如果使用匿名的参数,每一次调用会创建新的对象。可以将listener声明为成员变量,每次都复用同一个对象,并且可以使用静态域(static变量)。比如String类的域。

程序员小刘 1927

《Effective Java》学习笔记15--25

本栏是博主根据如题教材进行Java进阶时所记的笔记,包括对原著的概括、理解,教材代码的报错和运行情况。十分建议看过原著遇到费解地方再来参考或与博主讨论。致敬作者Joshua Bloch和各路翻译者们,以及为我提供可参考博文的博主们。 复制粘贴改格式好累,这几篇全都给出git地址,大家自己download下来看好了。或者想直接在浏览器上看可以考虑用这个名叫OctoTree的插件。安装教程网上大把,...

欢迎访问 花落的速度 的博客 322

《Effective java》第二版阅读笔记

18.接口优于抽象类 接口和抽象类都是java中定义类型、扩展功能的机制。 两者主要区别在于接口中全部是抽象方法,抽象类中可以包含抽象方法,也可以包含非抽象方法。 而接口优于抽象类的原因是,类可以实现多个接口,但只能继承一个抽象类,抽象类的使用受限。 假使对一个类进行扩展功能,可在implements后新增接口实现,如Comparable引进到java中后,更新了许多现有类。同时接口也是mixin...

张晨雪的博客 664

《Effective Java》读书笔记,2024年阿里Android高级面试题分享

除此之外,为了任何其他的目的而定义接口是不恰当的。说白了,定义接口是为了接口的行为。有一种接口是常量接口,这是对接口的不良使用。因为常量是实现细节,不应该泄漏出去。对类的用户来说没有价值,反而会干扰。而且如果非final类实现了常量接口,它的所有子类的命名空间也会被接口中的常量所“污染”。定义常量应该用枚举或者不可实例化的工具类。标记接口是没有包含方法声明的接口,而只是知名一个类实现了具有某种属性的接口。例如Serializable。如果想要定义类型,一定要使用接口第七章方法。

weixin_58134620的博客 899

Effective Java

Effective Java 由于书本内容太枯燥,看不下去,只能对着抄。。加油ヾ(◍°∇°◍)ノ゙ 文章目录第一章 引言第二章 创建和销毁对象第1条 用静态工厂方法代替构造器第2条 遇到多个构造器参数时要考虑构建器第3条 用私有构造器或者枚举类型强化Singleton属性第4条 通过私有构造器强化不可实例化的能力第5条 优先考虑依赖注入来引用子源第6条 避免创建不必要的对象第7条 消除过期的对象引用第8条 避免使用终结方法和清除方法第9条 try-with-resources优先于try-finally第

lyw4631的博客 471
上一篇: Effective Java笔记(22)接口只用于定义类型
下一篇: Effective Java笔记(24)静态成员类优于非静态成员类
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值