effective-java-day001

  1. 考虑使用静态工厂方法替代构造方法
    下面是一些静态工厂方法的常用名称。以下清单这是列出了其中的一小部分:
// from —— 类型转换方法,它接受单个参数并返回此类型的相应实例,例如:
Date d =Date.from(instant);

//of —— 聚合方法,接受多个参数并返回该类型的实例,并把他们合并在一起,例如:
Set<Rank>faceCards = EnumSet.of(JACK, QUEEN, KING);

//valueOf —— from 和 to 更为详细的替代 方式,例如:
BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);

//instance 或 getinstance —— 返回一个由其参数 (如果有的话) 描述的实例,但不能说它具有相同的值,
//例如:
StackWalker luke = StackWalker.getInstance(options);

//create 或 newInstance —— 与 instance 或 getInstance 类似,除此之外该方法保证每次调用返回
//一个新的实例,例如:
Object newArray = Array.newInstance(classObject, arrayLen);

// getType —— 与 getInstance 类似,但是在工厂方法处于不同的类中的时候使用。getType 中的
//Type 是工厂方法返回的对象类型,例如:
FileStore fs = Files.getFileStore(path);

//newType —— 与 newInstance 类似,但是在工厂方法处于不同的类中的时候使用。newType中的Type
// 是工厂方法返回的对象类型,例如:
BufferedReader br = Files.newBufferedReader(path);

//type —— getType 和 newType 简洁的替代方式,例如:
List<Complaint> litany = Collections.list(legacyLitany);

  1. 当构造方法参数过多时使用 builder 模式
    下面是一个可伸缩构造方法
package effective;

/**
 * 美团外卖点菜填写信息
 * @Author: hyh
 * @Date: 2021/9/10 16:27
 **/
public class Order {
    // 菜名 必填
    private final String name;
    // 数量 必填
    private final int num;
    // 地址 必填
    private final String address;
    // 电话 必填
    private final long phone;
    
    // 性别 选填
    private final String sex;
    
    // 爱好 选填
    private final String hobby;
    
    // 工作 选填
    private final String job;

    public Order(String name, int num, String address, long phone) {
        // 调用下一个
        this(name,num,address,phone,"未知");
    }

    public Order(String name, int num, String address, long phone, String sex) {
        this(name,num,address,phone,"未知","未知");
    }

    public Order(String name, int num, String address, long phone, 
    String sex, String hobby) {
        this(name,num,address,phone,"未知","未知","未知");
    }

    public Order(String name, int num, String address, long phone,
     String sex, String hobby, String job) {
        this.name = name;
        this.num = num;
        this.address = address;
        this.phone = phone;
        this.sex = sex;
        this.hobby = hobby;
        this.job = job;
    }



   public void toPrint() {
    System.out.println("Order{" +
            "菜名='" + name + '\'' +
            ", 数量=" + num +
            ", 收货地址='" + address + '\'' +
            ", 收货人电话=" + phone +
            ", 收货人性别='" + sex + '\'' +
            ", 爱好='" + hobby + '\'' +
            ", 工作='" + job + '\'' +
            '}');
}

    public static void main(String[] args) {
        // 需要几个参数填几个
        Order order = new Order("北京烤鸭", 4, "西安钟楼", 18888888888L);
        order.toPrint();
    }
}
输出:
Order{菜名='北京烤鸭', 数量=4, 收货地址='西安钟楼', 收货人电话=18888888888,
 收货人性别='未知', 爱好='未知', 工作='未知'}

可伸缩构造方法模式是有效的,但是当有很多参数时,很难编写客户端代码,而且很难读懂它。而且读者不知道这些值是什么意思,并且必须仔细地去数参数才能找到答案。一长串相同类型的参数可能会导致一些 bug。如果客户端不小心写反了两个这样的参数,编译器并不会报错,但是程序在运行时会出现与预期不一致的行为

当在构造方法中遇到许多可选参数时,另一种选择是 JavaBeans 模式,在这种模式中,调用一个无参的构造方法来创建对象,然后调用 setter 方法来设置每个必需的参数和可选参数:

package effective;

/**
 * 美团外卖点菜填写信息
 * @Author: hyh
 * @Date: 2021/9/10 16:27
 **/
public class Order {
    // 菜名 必填
    private String name;
    // 数量 必填
    private int num;
    // 地址 必填
    private String address;
    // 电话 必填
    private long phone;

    // 性别 选填
    private String sex;

    // 爱好 选填
    private String hobby;

    // 工作 选填
    private String job;

    public Order() {
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public void setPhone(long phone) {
        this.phone = phone;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public void toPrint() {
        System.out.println("Order{" +
                "菜名='" + name + '\'' +
                ", 数量=" + num +
                ", 收货地址='" + address + '\'' +
                ", 收货人电话=" + phone +
                ", 收货人性别='" + sex + '\'' +
                ", 爱好='" + hobby + '\'' +
                ", 工作='" + job + '\'' +
                '}');
    }

    public static void main(String[] args) {
        Order order = new Order();
        order.setName("北京烤鸭");
        order.setNum(4);
        order.setPhone(18888888888L);
        order.setAddress("西安钟楼");
        order.toPrint();
    }
}

由于构造方法被分割成了多次调用,所以在构造过程中 JavaBean 可能处于不一致的状态。 该类仅通过检查构造函数参数的有效性,而没有强制的一致性措施。在不一致的状态下尝试使用对象可能会导致一些错误,这些错误与平常代码的 BUG 很是不同,因此很难调试。

builder模式:结合了可伸缩构造方法模式的安全性和 JavaBean 模式的可读性。客户端不直接构造所需的对象,而是调用一个包含所有必需参数的构造方法 (或静态工厂) 得到获得一个 builder 对象。然后,客户端调用 builder 对象的与setter 相似的方法来设置你想设置的可选参数。最后,客户端调用 builder 对象的一个无参的build 方法来生成对象,该对象通常是不可变的。Builder 通常是它所构建的类的一个静态成员类

package effective;

/**
 * 美团外卖点菜填写信息
 *
 * @Author: hyh
 * @Date: 2021/9/10 16:27
 **/
public class Order {
    // 菜名 必填
    private final String name;
    // 数量 必填
    private final int num;
    // 地址 必填
    private final String address;
    // 电话 必填
    private final long phone;

    // 性别 选填
    private final String sex;

    // 爱好 选填
    private final String hobby;

    // 工作 选填
    private final String job;

    private Order(Builder builder) {
        this.name = builder.name;
        this.num = builder.num;
        this.address = builder.address;
        this.phone = builder.phone;
        this.sex = builder.sex;
        this.hobby = builder.hobby;
        this.job = builder.job;
    }

    public static class Builder {

        // 菜名 必填
        private final String name;
        // 数量 必填
        private final int num;
        // 地址 必填
        private final String address;
        // 电话 必填
        private final long phone;

        // 性别 选填
        private String sex = "未知";

        // 爱好 选填
        private String hobby = "未知";

        // 工作 选填
        private String job = "未知";

        public Builder(String name, int num, String address, long phone) {
            this.name = name;
            this.num = num;
            this.address = address;
            this.phone = phone;
        }

        public Builder sex(String sex) {
            this.sex = sex;
            return this;
        }

        public Builder hobby(String hobby) {
            this.hobby = hobby;
            return this;
        }

        public Builder job(String job) {
            this.job = job;
            return this;
        }

        public Order build() {
            return new Order(this);
        }
    }


    public void toPrint() {
        System.out.println("Order{" +
                "菜名='" + name + '\'' +
                ", 数量=" + num +
                ", 收货地址='" + address + '\'' +
                ", 收货人电话=" + phone +
                ", 收货人性别='" + sex + '\'' +
                ", 爱好='" + hobby + '\'' +
                ", 工作='" + job + '\'' +
                '}');
    }

    public static void main(String[] args) {
        Order order = new Order.Builder("北京烤鸭", 4, "西安钟楼", 18888888888L)
                .hobby("爱打游戏").build();
        order.toPrint();
    }
}
输出:
Order{菜名='北京烤鸭', 数量=4, 收货地址='西安钟楼', 收货人电话=18888888888, 
收货人性别='未知', 爱好='爱打游戏', 工作='未知'}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值