一、用静态工厂方法替代构造器

Boolean(基本类型boolean的装箱类)的简单示例。这个方法将boolean基本类型值转换成了一个Boolean对象引用:

  1. public final class Boolean implements java.io.Serializable,
  2. Comparable<Boolean>
  3. {
  4. //对应于原始值true的Boolean对象。
  5. public static final Boolean TRUE = new Boolean(true);
  6. //对应于原始值false的Boolean对象。
  7. public static final Boolean FALSE = new Boolean(false);
  8. //分配一个代表value参数的Boolean对象。
  9. //注意:很少适合使用此构造函数。除非需要新实例,否则通常使用静态工厂value0f(boolean)是更好的选择。
  10. //它可能会产生明显更好的时空性能。
  11. //参数:value — Boolean .
  12. public Boolean(boolean value) {
  13. this.value = value;
  14. }
  15. //返回表示指定boolean值的Boolean实例。如果指定的boolean值为true,则此方法返回Boolean.TRUE ;
  16. //Boolean.TRUE为true。如果为false,则此方法返回Boolean.FALSE。如果不需要新的Boolean实例,
  17. //则通常应优先于构造方法Boolean(boolean)此方法,因为此方法可能会产生明显更好的时空性能。
  18. public static Boolean valueOf(boolean b) {
  19. return (b ? TRUE : FALSE);
  20. }
  21. }

1.1-静态工厂的优势

  1. 它们有名称,如果构造器的参数本身没有确切地描述正被返回的对象,那么具有适当名称的静态工厂会更容易使用,产生的客户端代码也更易于阅读。例如:构造器BigInteger ( int,int,Random)返回的BigInteger可能为素数,如果用名为BigInteger.probablePrime的静态工厂方法来表示,显然更为清楚。
  2. 不必在每次调用它们的时候都创建一个新对象。

    1. public static void main(String[] args) {
    2. Boolean b1 = Boolean.valueOf(true);
    3. Boolean b2 = Boolean.valueOf(true);
    4. System.out.println(b1 = b2);
    5. }
    6. //运行结果为true,b1和b2是同一个对象的应用
  3. 它们可以返回原返回类型的任何子类型的对象。这样我们在选择返回对象的类时就有了更大的灵活性。

  4. 所返回的对象的类可以随着每次调用而发生变化,这取决于静态工厂方法的参数值。只要是已声明的返回类型的子类型,都是允许的。返回对象的类也可能随着发行版本的不同而不同。
  5. 方法返回的对象所属的类,在编写包含该静态工厂方法的类时可以不存在。这种灵活的静态工厂方法构成了服务提供者框架(Service ProviderFramework)的基础,例如JDBC(Java数据库连接)API。服务提供者框架是指这样一个系统:多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把它们从多个实现中解耦出来。

    1. 服务提供者框架中有三个重要的组件:
      1. 服务接口(Service Interface),这是提供者实现的;
      2. 提供者注册API ( Provider Registration API),这是提供者用来注册实现的;
      3. 服务访问API (Service Access API),这是客户端用来获取服务的实例。
    2. 第四个组件,服务提供者接口(Service Provider Interface)是可选的,它表示产生服务接口之实例的工厂对象。如果没有服务提供者接口,实现就通过反射方式
    3. 对于JDBC来说,Connection就是其服务接口的一部分,DriverManager.registerDriver是提供者注册API, DriverManager.getConnection是服务访问API,Driver是服务提供者接口。

      1.2-静态工厂的缺点

  6. 类如果不含公有的或者受保护的构造器,就不能被子类化。

  7. 程序员很难发现它们。在API文档中,它们没有像构造器那样在API文档中明确标识出来,因此,对于提供了静态工厂方法而不是构造器的类来说,要想查明如何实例化一个类是非常困难的。

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

    创建对象我们可以使用构造器和JavaBean的方式,还有第三种替代方法,它既能保证像重叠构造器模式那样的安全性,也能保证像JavaBeans模式那么好的可读性。这就是建造者(Builder)模式形式。它不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器(或者静态工厂),得到一个builder对象。然后客户端在builder对象上调用类似于setter的方法,来设置每个相关的可选参数。最后,客户端调汭无参的build方法来生成通常是不可变的对象。这个builder通常是它构建的类的静态成员类(详见第24条)。下面就是它的示例: ```java public class GirlFriend {

    private String name; private int age; private int height;

    public static class Build{

    1. private String name;
    2. private int age;
    3. private int height;
    4. public Build(String name){
    5. this.name = name;
    6. }
    7. public Build setAge(int age){
    8. this.age = age;
    9. return this;
    10. }
    11. public Build setHeight(int height){
    12. this.height = height;
    13. return this;
    14. }
    15. public GirlFriend build(){
    16. return new GirlFriend(this);
    17. }

    }

    @Override public String toString() {

     return "GirlFriend{" +
             "name='" + name + '\'' +
             ", age=" + age +
             ", height=" + height +
             '}';
    

    }

    private GirlFriend(Build build){

     this.name = build.name;
     this.age = build.age;
     this.height = build.height;
    

    }

    public static void main(String[] args) {

     GirlFriend build = new GirlFriend.Build("杨颖").setAge(18).build();
     System.out.println(build.toString());
    

    } } //输出:GirlFriend{name=’杨颖’, age=18, height=0}

```