Java - 使可访问性最小化
模块设计是否良好,有个重要的因素在于,相对外部模块是否隐藏内部数据以及实现细节。
设计良好的模块会隐藏实现细节,并将API与其实现隔离开来。
模块之间通过API进行通信,对于内部工作情况互不可见。
即,封装(encapsulation)——软件设计的基本原则之一。
为什么要封装?
通过封装可以有效地接触各个模块之间的耦合关系,使这些模块可以独立地开发、测试、优化、使用、理解和修改。
即:
- 可以增加开发效率,模块可以并行开发。
- 封装可以减轻维护的负担,可以更有效的进行优化,且不会影响其他模块的正确性。
- 提高了软件的可重用性,模块在其他环境中也可以被使用。
(PS:回想我自己以前用php写网站时根本没有这些概念也不影响开发工作。当时觉得没什么,因为是我一个人写的,再加上后来也没有再扩展,于是没有了种种体会。)
可以通过访问控制保证封装。
一个实体的可访问性是通过实体声明所在的位置和访问修饰符共同决定的。
建议尽可能地使每个类或者成员不被外界访问。
对于顶层的类和接口只有两种访问级别:包级私有和公有。
更小的可访问性代表更小的兼容性,在以后发行的版本中可以放心对其进行修改。
如果是公有的,则需要一直考虑客户的行为。(PS:如果一个顶层类只是在某一个类的内部被用到,则可以声明为私有静态内部类。)
比如这样一个类,这样做在以后的版本中便无法改变表示方式,而且无法加入任何约束:
class Point {
public double x;
public double y;
}
于是正如很多人的习惯那样,对于公有类用公有的访问方法替代公有field以保证数据在类内部的灵活性:
class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public void setX(double x) {
this.x = x;
}
public void setY(double y) {
this.y = y;
}
}
(PS:当然,有些常见的类并没有遵守这一规则比如java.awt.Point、java.awt.Dimension。
但原作者也明确指出这些类不值得效仿。)
如果一个field只能是公有的,且允许将其声明为final,则危害能少一些。
我们仍然可以通过公有的访问方法访问该field。
但不能用公有的setter,而是通过构造器加入约束:
public final class Time {
private static final int HOURS_PER_DAY = 24;
private static final int MINUTES_PER_HOUR = 60;
public final int hour;
public final int minute;
public Time(int hour, int minute) {
if (hour < 0 || hour >= HOURS_PER_DAY)
throw new IllegalArgumentException("Hour: " + hour);
if (minute < 0 || minute >= MINUTES_PER_HOUR)
throw new IllegalArgumentException("Min: " + minute);
this.hour = hour;
this.minute = minute;
}
// Remainder omitted
}
对于成员(field,method,嵌套类,嵌套接口)有4种访问级别:
- private
- package-private(default)
- protected
- public
当设计了类的公有API后,我们将所有成员都变成私有。
然后发现同一个包内的另一个类也需要访问这个成员,于是便修改访问级别。如果这种事情经常发生则应该检查设计是否合理。
虽然package和private级别的成员都是类实现的一部分,不会影响导出的API。
但,该类实现了Serializable时则另当别论。
如果使用protected修饰,则需要注意,该成员时导出的API的一部分。
另外,实例field尽量不要设置为公有。如果一个field不是final或者是一个指向可变对象的final field,公有的访问级别会破坏该field的不可变性,它已不是一个内部的数据表示,而且非线程安全。
当然,这对于长度!=0的数组也是一样的。
如果需要将某数组声明为公有,可以尝试以下方式:
private static final Thing[] PRIVATE_VALUES = {...};
public static final List<Thing> VALUES =
Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
或者可以使用clone,每次都拷贝一个数组:
private static final Thing[] PRIVATE_VALUES = {...};
public static final Thing[] values(){
return PRIVATE_VALUES.clone();
}
Java - 使可访问性最小化的更多相关文章
- 《Effective Java》笔记 使类和成员的可访问性最小化
类和接口 第13条 使类和成员的可访问性最小化 1.设计良好的模块会隐藏所有的实现细节,把它的API与实现清晰的隔离开来,模块之间只通过它们的API进行通信,一个模块不需要知道其他模块的内部工作情况: ...
- Effective Java 第三版——15. 使类和成员的可访问性最小化
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- EffectiveJava(13)使类和成员的可访问性最小化
1.为什么要使类和成员可访问性最小化 它可以有效地解除组成系统的各模块之间的耦合关系,使得这些模块可以独立的开发 测试 优化 使用 理解和修改.提高软件的可重用性 2.成员的访问级别 私有(priva ...
- Effective Java —— 使类和成员的可访问性最小化
本文参考 本篇文章参考自<Effective Java>第三版第十五条"Minimize the accessibility of classes and members&quo ...
- Effective Java --使类和成员的可访问性最小化
尽可能地降低可访问性 接口和成员变量访问级别四种访问级别: 私有的(private) --- 只有在生命该成员的顶层类内部才可以访问 包级私有的(package-private) --- 缺省的&qu ...
- Effective Java:Ch4_Class:Item13_最小化类及其成员的可访问性
要区别一个模块是否设计良好,最重要的因素是,对于其他模块而言该模块隐藏其内部数据和其他实现细节的程度.设计良好的模块应该隐藏所有实现细节,将API与其实现清晰地隔离开来.这样,模块之间通过他们的API ...
- Effective Java 第三版——17. 最小化可变性
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——57. 最小化局部变量的作用域
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- VC++ 如何使窗体最大化或是最小化
最大化最小的使得的函数是 ShowWindow函数 ShowWindow(SW_SHOWMINIMIZED);//最小化 ShowWindow(SW_SHOWMAXIMIZED);//最大化 Show ...
随机推荐
- TestNG参数化之@Parameters传参
通过TestNG实现参数话常用两种方式,一种是借助 @Parameters读取testng.xml中参数,一种是使用@DataProvider注解传参. 此次主要讲解XML传参,语法:在java类中定 ...
- java—实现一个监听器HttpServletRequest的创建销毁、在线人数 (56)
在JavaWeb中的监听器分类 在Javaweb中存在三个被监听对象: HttpServletRequest HttpSessoin ServletContext 监听者 被监听者 监听到事件对象 H ...
- php中的XML DOM(11)
7.创建节点 在dom操作中,增删改操作必须要找父节点 1.DOMElement DOMDocument::createElement ( string $name [, string $value ...
- JAVA构造函数(方法)
一.什么是构造函数 java构造函数,也叫构造方法,是java中一种特殊的函数.函数名与相同,无返回值. 作用:一般用来初始化成员属性和成员方法的,即new对象产生后,就调用了对象了属性和方法. 在现 ...
- FlowPortal-BPM——数据库交互:创建新接口(类库)—将数据提交给其他程序使用
使用到的是“流程设计”→“自定义插件” 一.创建新类库 (1)新建类库→引用文件 (2)新建ado.net数据访问类(要操作的数据库) (3)右键类库名称→属性→生成→输出→路径:安装目录下UserD ...
- QuantLib 金融计算——数学工具之数值积分
目录 QuantLib 金融计算--数学工具之数值积分 概述 常见积分方法 高斯积分 如果未做特别说明,文中的程序都是 Python3 代码. QuantLib 金融计算--数学工具之数值积分 载入模 ...
- 蓝牙4.0BLE抓包(一) - 搭建EN-Dongle工作环境 使用EN-Dongle抓包 nRF51822
版权声明:本文为博主原创文章,转载请注明作者和出处. 蓝牙4.0 BLE的开发过程中,使用抓包器进行抓包分析无疑会极大地提高我们的开发效率,同时能帮我们快速的定位问题.对于初学者 ...
- (C/C++) 指向函數的指標
最近再跟指標做朋友, 正好遇到函數與指標. 其實函數也在程式內也是有屬於自己的位址 所以指標一樣能指向函數, 在此釐清自己的觀念以及記錄下來. #include <stdio.h> #in ...
- python实现数据库增删改查
column_dic = {"id": 0, "name": 1, "age": 2, "phone": 3, &quo ...
- xilinx DMA IP核(二) —— 文档阅读
本笔记不记录DMA的Scatter/Gather特性.DMA上有三种总线:AXI4-LIte(对寄存器进行配置),AXI4-Memory Map(用于与内存交互)和AXI4 Stream(用于与外设交 ...