现在的位置: 首页 > 综合 > 正文

第13条:使类和成员的可访问性最小化

2013年09月10日 ⁄ 综合 ⁄ 共 2281字 ⁄ 字号 评论关闭

概念:
要区别设计良好的模块与设计不好的模块,最重要的因素在于,这个模块对于外部的其他模块而言,是否隐藏其内部数据和其他细节。
设计良好的模块会隐藏所有的实现细节,把他的API和他的实现清晰的分割开来。然后,模块之间通过他们之间的API进行通信,一个模块不需要知道其他模块的内部情况。
这个概念被成为信息隐藏(information hiding)或封装(encapsulation),是软件设计的基本 原则之一。

优点:
信息隐藏只所以非常重要有许多原因,其中大多数理由都源于这样一个事实:
他可以有效的解除系统组成各模块之间的耦合关系,是的这些模块可以独立的开发、测试、优化、使用、理解和修改。
这样可以加快系统开发的速度,因为这些模块可以并发开发。
他也减轻了维护的负担,因为程序员可以更快的理解这些模块,并且在调试他们的时候不影响其他的模块。
虽然信息隐藏本身无论是对内还是对外,都不会带来更好的性能,但是他可以有效的调节性能:
一旦完成一个系统,并通过剖析哪些模块影响了系统性能,那些模块可以进一步优化,而不影响到其他模块的正确性。
信息隐藏提高了软件的,因为模块之间并不紧密相连,除了开发这些模块所使用的坏境之外,他们在其他坏境中往往也很有用。
最后,信息隐藏也降低了构建大型系统的风险,因为即使整个系统不可用,但是这些独立的模块却有可能是可用的。

Java程序设计提供了很多机制(facility)来协助信息隐藏。
访问控制机制(access control)决定了类、接口和成员的可访问性(accessibility)。

对于顶层(非嵌套的)类和接口,只要两种可能的访问机制:包私有的(package-private)和共有的(public)。
如果是私有的,你可以对他进行替换、修改或者删除,而无需担心会影响到现有的客户端程序。
但是,如果你把它设置为共有的,你有责任永远支持他,以保证他们的兼容性。

然后,降低不必要的公有类的可访问性,比降低包级别私有的顶层类的更重要的多:
因为公有类是包的API的一部分,而包级私有的顶层类已经是这个包的实现的一部分。

对于成员(域、方法、嵌套类和嵌套接口)有四种可能的访问级别:
私有的(private)--只要在生命该成员的顶层类内部才可以访问这个成员。
包级私有的(package-private)--声明该成员的包内部的任何类都可以访问这个成员。从技术上讲,也也称为“缺省(default)访问级别”。
受保护的(protected)--比包私有的多了个子类可以访问。
共有的(public)--在任何地方都可以访问该成员。

实例域决不能是公有的。如果域是非final的,或者是一个指向可变对象的final引用,那么一旦是这个域成为共有的,就放弃了对存储在这个域中的值限制的能力。
包含共有可变域的类并不是线程安全的。

类具有共有的静态的final数组域,或者返回这个域的访问方法,这几乎总是错误的。

可以使共有数组变成私有的,并返回一个公有的不可变列表。

private static final Thing[] PRIVATE_VALUES = {...};
public static final List<Ting> VALUES = Collecations.unmodifiableList(Arrays.asList(PRIVATE_VALUES));

或者:

private static final Thing[] PRIVATE_VALUES = {...};
public static final Thing[] values() {
	return PRIVATE_VALUES.clone;
}

Demo:
package cn.partner4java.test;

import java.util.LinkedList;
import java.util.List;

public class ListTest {
	private List<String> names = new LinkedList<String>();

	public List<String> getNames() {
		return names;
	}

	public void setNames(List<String> names) {
		this.names = names;
	}
	
	public List<String> getCloneNames() {
		List<String> namesClone = new LinkedList<String>();
		namesClone.addAll(names);
		return namesClone;
	} 


	public static void main(String[] args) {
		ListTest listTest = new ListTest();
		listTest.getNames().add("wang");
		listTest.getNames().add("chang");
		listTest.getNames().add("long");
		
		List<String> namesG = listTest.getNames();
		List<String> namesCG = listTest.getCloneNames();
		namesG.set(2, "ming");
		System.out.println(listTest.getNames());
		System.out.println(namesG);
		System.out.println(namesCG);
//		后台打印:
//		[wang, chang, ming]
//		 [wang, chang, ming]
//		 [wang, chang, long]
	}

}

抱歉!评论已关闭.