Effective Java 项目实战

Book:《Effective Java》

Program: SSM Framework


目录


1. “创建和销毁对象”

1.1 考虑使用静态工厂方法代替构造器

  1. 静态工厂方法与设计模式的工厂方法模式不同,并非直接对应
  2. 静态方法可看做替代构造器的方案,对外暴露静态工厂方法,将构造器设为private

优势

  • 静态工厂方法可以具有名称,比构造方法更加直观,可管理重载的构造方法
  • 不必在每次调用时创建一个新对象,可以复用原有对象
  • 可以任意子类型的对象,通过向上转型实现
  • 创建参数化类型实例时,使代码更简洁 => 使用泛型,进行类型推导,根据传入参数不同,返回不同结果,而不用直接向构造器传入特定的参数

缺点

  • 如果不包含共有的或者受保护的构造器,就不能被子类化 => 同时,若不包含public的构造方法,将不能通过反射创建此类的对象,在使用到动态创建对象时,应将无参构造方法设为public

命名习惯

  • valueOf() / of() 用于类型转换时
  • getInstance() 获取实例,用于单例模式
  • newInstance() 创建新的实例
  • getType() 用于获取对象的类型

使用场景

在构造函数重载的情况下,可以考虑使用静态工厂,对构造方法进行封装。

1.2 遇到多个构造器参数时考虑用构建器

  1. 当参数较多时,避免使用构造函数进行参数的初始化,因为其与顺序有关,且不易阅读,这个阈值大约在3、4个参数时
  2. 从代码格式上讲,考虑最普通的参数赋值,即使用setter,但setter过于啰嗦,尤其是参数多时不宜阅读。
    使用构建器或者构建者模式将有利于更加清晰的代码阅读
  3. 从更高层面来讲,即多线程的情况时,举个例子,我同时setter5个属性,那么当setter到一半时,这个对象被改变了,怎么办?如何确保前后状态一致?或者说:setter的构造过程被分到了几个调用中,在构建Javabean时可能处于不一致状态
  4. 一个线程安全的做法,就是“冻结”对象,即一次性生成不可变的对象,那么这就是构建者模式的一种。

构建器生成不可变对象

一个使用了《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;
    }
}

猜你喜欢

转载自blog.csdn.net/wsh596823919/article/details/82461105