EffectiveJava-考虑用静态工厂方法代替构造器

创建对象的方式有很多种,最常见的是利用构造器+new关键字,另外一种常见的方式是用静态工厂方法创建,例如包装类中的value of(int x)、集合工厂类Collections中创建各种不同类型集合的方法。

那么,既然通过这两种方式都可以创建类的实例,这两种方式有什么区别呢?

  • 静态工厂方法与构造器不同的第一大优势在于,它有名称。
    对于这一点,要从静态工厂方式和构造器两个方面分别进行说明。 在利用构造函数创建具有不同状态的对象时,唯一的途径就是通过构造函数参数列表来区分,例如:
class Demo{
        private int x = 0;
        private int y = 0;
        public Demo(int x){
            this.x = x;
        }
        public Demo(int x, int y){
            this.x = x;
            this.y = y;
        } 
}

我们可以通过两种构造器来创建不同状态的Demo对象,但这带来的一个问题是:如果没有参考文档,客户端程序员往往不知所云,即可读性差。
与之相反,利用静态工厂方法可以在方法签名的语义层面加以区分,例如:

class Demo{
    private int x = 0;
    private itn y = 0;
    private Demo(int x){
        this.x = x;
    }
    private Demo(int x, int y){
        this.x = x;
        this.y = y;
    }

    public static Demo createOneParamDemo(int x){
        return new Demo(x);
    }

    public static Demo createTwoParamDemo(int x, int y){
        return new Demo(x, y);
    }

}

这样,我们就可以通过慎重的选择方法签名来对创建不同的Demo对象加以区分。

  • 静态工厂与构造器不同的第三大优势在于,他们可以返回原返回类型的任何子类型的对象

这样,我们在选择返回对象的类时,就有了更大的灵活性,这种灵活性的一种应用是,API可以返回对象,同时又不会使对象的类变成共有的,以这种方式隐藏实现类会使API变得非常简洁,这种技术适用于基于接口的框架。例如Java Collections Framework。例如:

public static  List synchronizedList(List list) {
        return (list instanceof RandomAccess ?
                new SynchronizedRandomAccessList<>(list) :
                new SynchronizedList<>(list));
}

public static  Map synchronizedMap(Map m) {
        return new SynchronizedMap<>(m);
}

这是一个非常好的例子,如果没有Collections类,我们需要面对的是几十个Java Collection Framework中的构造函数,同时,还有一点不得不提,Collections屏蔽了具体的细节,类的实现者可以对内部进行任意优化或修改而不影响调用者,这是非常重要的。

  • 静态工厂方法的第三大优势在于,在创建参数和类型的实例时,它使代码变得更加简洁

用两个例子来说明这一点区别:

//面对构造器创建对象
Map<String, String> map = new HashMap<String, String>();

//用静态工厂方法
public static <K, V> HashMap<K, V> newInstance(){
    return new HashMap<K, V>();
}
Map<String, String> map = HashMap.newInstance();

虽然在实现上看起来代码量更大了, 但是对于调用者而言,更简单了。

有有点就会哟缺点,静态工厂方法有两个明显的缺陷:

  • 类如果不含有共有的或者受保护的构造器,就不能被子类实例化,即不能被继承

  • 创建对象的静态工厂方法与其他静态方法并无区别



简而言之,静态工厂方法和公有构造函数都各有用处,需要理解他们各自的长处,单通常来说,优先考虑静态工厂方法。

你可能感兴趣的:(Java基础)