Effective Java学习笔记(一)

1.用静态工厂方法代替构造器

类可以提供一个共有的静态工厂方法,它只是一个返回类的实例的静态方法。

下面是一个来自 Boolean (基本类型 boolean 装箱类)的简单示例 这个方法将 boolean 基本
类型值转换成了 olean 对象引用:
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE;
}

静态工厂方法的优势:

  1. 静态工厂方法与构造器不同的第一大优势在于,它们有名称。例如,构造器 Biginteger (int , int, Random )返回的Biginteger 可能为素数,如果用名为 ginteger.probablePrime 的静态工厂方法来表示,显然更为清楚 。
  2. 静态工厂方法与构造器不同的第二大优势在于,不必在每次调用它们的时候都创建一个新对象。静态工厂方法能够为重复的调用返回相同对象,这样有助于类总能严格控制在某个时刻哪些实例应该存在。
  3. 静态工厂方法与构造器不同的第三大优势在子,它们可以返回原返回类型的任何子类型的对象。
  4. 静态工厂的第四大优势在于,所返回的对象的类可以随着每次调用而发生变化,这取决于静态工厂方法的参数值 只要是已声明的返回类型的子类型,都是允许的 返回对象的类也可能随着发行版本的不同而不同。
  5. 静态工厂的第五大优势在于,方法返回的对象所属的类,在编写包含该静态工厂方法的类时可以不存在。
    在这里插入图片描述

2.遇到多个构造器参数时要考虑使用构建器

静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数。
遇到许多可选的构造器参数的时候,还有第二种代替办法,即 JavaBeans 模式,在这种模式下,先调用一个无参构造器来创建对象,然后再调用 sette 方法来设置每个必要的参数,以及每个相关的可选参数。

遗憾的是, javaB eans 模式自身有着很严重的缺点 因为构造过程被分到了几个调用中,在构造过程中 Java Bean 可能处于不一致的状态。与此相关的另一点不足在于, Java Beans 模式使得把类做成不可变的可能性不复存在 (详见第 17 条),这就需要程序员 付出 额外的努力来确保的线程安全。

幸运的是,还有第 3种替代方法,它既能保证像重叠构造器模式那样的安全性,也能保证像 Ja vaB ean 模式那么好的可读性 这就是建造者( Bui lder )模式的一种形式 它不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器(或者静态工厂),得到一个 buil der 对象 然后客户端在 bu ld er 对象上调用类似于setter 的方法,来设置每个相关的可选参数 最后 客户端调 无参 build 方法来生成通常是不可变的对象,这个 builder 通常是它构建的类的静态成员类.

在这里插入图片描述
在这里插入图片描述
注意NutritionFacts是不可变的,所有默认的参数值都单独放在一个地方。builder的设值方式返回builder本身,以便把调用连接起来,得到一个流式API。

与构造器相比,builder的微略优势在于,它可 以有 个可变( varargs )参数 。因为builder 是利用单独的方法来设置每一个参数 。此外,构造器还可以将多次调用某一个方法而传人的参数集 中到一个域中。

Builder模式十分灵活,可以利用单个builder构建多个对象。builder的参数可以在调用build方法来创建对象期间进行调整,也可以随着不同的对象而改变。builder可以自动填充某些域,例如每次创建对象时增加序列号。
Builder 模式的确 有它自身的不足。 为了创建对象 ,必须先创建它的构建器。 虽然创建这个构建器的开销在实践中可能不那么明显 但是在某些十分注重性能的情况下,可能就成问题了 Builder 模式还 比重叠构造器模式更加冗 ,因此它只在有很多参数的时候才使用,比如 个或者更多个参数 但是记住,将来你可能需要添加参数 如果一开始就使用构造器或者静态 工厂,等到类需要多个参数时才 舔加构造器,就会无法控制,那些过时的构造器或者静态工厂显得十分不协调 此,通常最好一开始就使用构建器。

简而言之, 如果类的构造器或者静态工厂中具有多个参数,设计这种类时, Builde模式就是一种不错的选择, 特别是当大多数参数都是可选或者类型相同的时候 与使用重叠构造器模式相比,使用 Bui lder 模式的客户端代码将更易于 阅读和编写,构建器也比JavaBeans 更加安全。

3.用私有构造器或者枚举类型强化Singleton属性

singleton 是指仅仅被实例化一次的类。singleton 通常被用来代替一个无状态的对象,如函数,或者把鞋本质上唯一的系统组件。使类成为singleton 会使它的客户端测试变得十分困难,因为不可能给singleton 替换模拟实现,除非实现一个充当其类型的接口。
实现singleton 有两种常用方法。
一:公有静态成员是整个final 域。

puclic class Elvis {
//instance 保证了Elvis 的全局唯一性,只能生成一个实例
	public static final Elvis INSTANCE = new Elvis();
	private Elvis() {...}
	public void leaveTheBuilding () {}
}//end elvis

二:公有的成员是个静态工厂方法:

puclic class Elvis {
	private static final Elvis INSTANζE = new Elvis();
	private Elvis() {...}
	public static Elvis getInstance() { return INSTANCE; }
	public void leaveTheBuilding () {}
}

对于静态方法 Elvis.getinstance 的所有调用,都会返回同一个对象引用,所以,永远不会创建其他的 Elvis 实例(上述提醒依然适用)。
公有域方法的主要 势在于, API 很清楚 表明了这个类是一个 Singleton 公有的静态域是 fin al 的,所以该域总是包含相同的对象引用 第二个优势在于它更简单。
静态工厂方法的优势之一在于,它提供了灵活性 在不改变其 PI 的前提 下,我们可以改变该类是否应该为 singleton 的想法。第二个优势是,可以编写一个泛型singleton工厂。最后一个优势是,可以用方法引用作为提供者。
要将singleton类变成可序列化(serializable)仅仅是在声明中加上implement serialzable 是不够的。为了保证所有实例域是瞬时的,并提供一个readResolve方法。否则,每次反序列化一个序列化的实例时,都会创建一个新的实例。可以在Elvis 类中加入:

// readResolve method to preserve singleton property
private Object readResolve () { 
// Return the one true Elvis and let the garbage collector
return INSTANCE;

实现 Si ngleton 种方法是声明一个包含单个元素的枚举类型:

// Enum singleton - the preferred approach 
public enum Elvis { 
INSTANCE; 

public void leaveTheBuilding() { .. . }
  

这种方式防止多次序列化,经常成为实现singleton的最佳方法。如果singleton必须扩展一个超累,而不是扩展Enum的时候,则不宜使用这个方法(虽然可以声明枚举去实现接口)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值