第1章:序言
第2章:创建和销毁对象
第一条:用静态工厂方法代替构造器
一、静态工厂方法的优势
1、静态工厂方法有名字。
2、不必在每次调用静态工厂方法的时候都创建一个对象。
3、静态工厂方法可以返回类型的任何子类型的对象。
这样我们在选择返回对象的类时就有了更大的灵活性。
这种灵活的一种应用是,API可以返回对象,同时又不会使对象的类变成共有的。以这种方式隐藏实现类会使API变得非常简洁。这种技术适用于基于接口的框架,因为这种框架中,接口为静态工厂方法提供了自然返回类型。
Java8仍要求接口的所有静态成员都必须是共有的。
在Java9中允许接口有私有的静态工厂方法,但是静态域和静态成员类仍然是共有的。
4、所返回的对象的类可以随着每次调用而发生变化,这取决于静态工厂方法的参数值。
5、方法返回的独享所属的类,在编写包含该静态工厂方法的类时可以不存在。
这种灵活的静态工厂方法构成了服务提供者框架的基础,例如JDBC的API。
二、静态工厂方法的优缺点
1、类如果不含有公有的或受保护的构造器,就不能被子类化。
2、程序员很难发现它们。
三、静态工厂方法的惯用名称
1、from,类型转换方法
它只有单个参数,返回该类型的一个相对应的实例。
Date date = Date.from(instant);
2、of,聚合方法
带有多个参数,返回该类型的一个实例,把它们合并起来。
Set<Rank> faceCards = EnumSet.of(JACK,QUEEN,KING);
3、valueOf
比from和of更繁琐的一种替代方法。
BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
4、instance或者getInstance,返回的实例是通过方法的参数来描述的。
StackWalker luke = StackWalker.getInstance(options);
5、create或者newInstance,和instance和getInstance一样,但create和newInstance能够确保每次调用都返回一个新的实例。
Object newArray = Array.newInstance(classObject,arrayLen);
6、getType,像getInstance一样,但是在工厂方法处于不同类中的时候使用。Type表示工厂方法所返回的对象类型。
FileStore fs = Files.getFileStore(path);
7、newType,像newInstance一样。
8、type,getType和newType的简版
四、总结
简而言之,静态工厂方法和共有构造器都各有好处,我们需要理解它们各自的长处。
静态工厂方法更加合适,因此切忌第一反应就是提供公有的构造器,而不考虑静态工厂。
第2条:遇到多个构造器参数时要考虑使用构建器
静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数。
重叠构造器可行,但是当许多参数的时候,客户端代码会很难编写并且难以阅读。
JavaBeans模式
先调用无参构造器来创建对象,然后调用setter方法来设置每个必要的参数。
JavaBeans模式是我常用的方式,但是JavaBeans也有着很严重的缺点。因为构造过程被分到了几个调用中,在构造过程中JavaBean可能处于不一致的状态。类无法通过检验构造器参数的有效性来保证一致性。
幸运的是,还有第三种替代方法。它既能像重叠构造器模式的安全性,又能保证像JavaBeans模式那样的可读性。这就是建造者模式。
package com.guor.effective.chapter2.worker;public class Worker {private int id;private String name;private int age;private int sex;private String school;private String address;public static class Builder{private int id;private String name;private int age = 18;private int sex = 1;private String school = "辽宁石油化工大学";private String address = "辽宁省大连市高新园区";public Builder(int id, String name) {this.id = id;this.name = name;}public Builder age(int val){age = val;return this;}public Builder sex(int val){sex = val;return this;}public Builder school(String val){school = val;return this;}public Builder address(String val){address = val;return this;}public Worker build() {return new Worker(this);}}public Worker(Builder builder){int id = builder.id;String name = builder.name;int age = builder.age;int sex = builder.sex;String school = builder.school;String address = builder.address;}@Overridepublic String toString() {return "Worker{" +"id=" + id +", name='" + name + '\'' +", age=" + age +", sex=" + sex +", school='" + school + '\'' +", address='" + address + '\'' +'}';}
}
package com.guor.effective.chapter2.worker;public class Test {public static void main(String[] args) {Worker worker = new Worker.Builder(1,"郭晓彤").age(1).sex(1).school("中铁诺德幼儿园").address("中铁诺德滨海花园").build();System.out.println(worker.toString());}
}