Effective Java 项目实战
Book:《Effective Java》
Program: SSM Framework
目录
1. “创建和销毁对象”
1.1 考虑使用静态工厂方法代替构造器
- 静态工厂方法与设计模式的工厂方法模式不同,并非直接对应
- 静态方法可看做替代构造器的方案,对外暴露静态工厂方法,将构造器设为private
优势
- 静态工厂方法可以具有名称,比构造方法更加直观,可管理重载的构造方法
- 不必在每次调用时创建一个新对象,可以复用原有对象
- 可以任意子类型的对象,通过向上转型实现
- 创建参数化类型实例时,使代码更简洁 => 使用泛型,进行类型推导,根据传入参数不同,返回不同结果,而不用直接向构造器传入特定的参数
缺点
- 如果不包含共有的或者受保护的构造器,就不能被子类化 => 同时,若不包含public的构造方法,将不能通过反射创建此类的对象,在使用到动态创建对象时,应将无参构造方法设为public
命名习惯
- valueOf() / of() 用于类型转换时
- getInstance() 获取实例,用于单例模式
- newInstance() 创建新的实例
- getType() 用于获取对象的类型
使用场景
在构造函数重载的情况下,可以考虑使用静态工厂,对构造方法进行封装。
1.2 遇到多个构造器参数时考虑用构建器
- 当参数较多时,避免使用构造函数进行参数的初始化,因为其与顺序有关,且不易阅读,这个阈值大约在3、4个参数时
- 从代码格式上讲,考虑最普通的参数赋值,即使用setter,但setter过于啰嗦,尤其是参数多时不宜阅读。
使用构建器或者构建者模式将有利于更加清晰的代码阅读- 从更高层面来讲,即多线程的情况时,举个例子,我同时setter5个属性,那么当setter到一半时,这个对象被改变了,怎么办?如何确保前后状态一致?或者说:setter的构造过程被分到了几个调用中,在构建Javabean时可能处于不一致状态。
- 一个线程安全的做法,就是“冻结”对象,即一次性生成不可变的对象,那么这就是构建者模式的一种。
构建器生成不可变对象
一个使用了《EffectiveJava》中几个建议后的不可变安全对象的创建 ↓
public class UserDTO {
private final int userId;
private final String userName;
/** * hashCode缓存 */
private volatile int hashCode;
private UserDTO(UserDTO.Builder builder) {
userId = builder.userId;
userName = builder.userName;
}
public static class Builder implements MyBuilder<UserDTO> {
/** * final域,必须在构造器构造函数中赋值 */
private final int userId;
/** * 非final域,可设置默认值 */
private String userName = "default";
public Builder(int user_id, String user_name) {
this.userId = user_id;
}
public UserDTO.Builder userName (String val) {
userName = val;
return this;
}
@Override
public UserDTO build() {
return new UserDTO(this);
}
}
@Override
public boolean equals(Object obj) {
// 引用检测
if (obj == this) {
return true;
}
// 类型检测
if (!(obj instanceof UserDTO)) {
return false;
}
// 参数检测
if (this.userId != ((UserDTO) obj).getUserId()) {
return false;
}
if (!this.userName.equals(((UserDTO) obj).getUserName())) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = 17;
result = 31 * result + userId;
result = 31 * result + userName.hashCode();
hashCode = result;
}
return result;
}
@Override
public String toString() {
return "User@" + userId + "{" + userName + "}";
}
public int getUserId() {
return userId;
}
public String getUserName() {
return userName;
}
}