1.考虑用静态工厂方法代替构造器

静态方法与构造器不同的第一大优势在于,它们有名称

对于类的构造器来说他们的名字一定是一样的

下面的例子中 无论是戴眼镜的人还是不戴眼镜的人,他们都是通过NEW的时候传进来的参数.但是这样很不明确,构造器并没有完美的表达这个意思,可读性很差.

   public class person {
    private String name;
    private int sex;
    private boolean glasses;

    // 普通的人
    public person(String name, int sex) {
        this.name = name;
        this.sex = sex;
    }

    // 带眼镜的人
    public person(String name, int sex, boolean glasses) {
        this.name = name;
        this.sex = sex;
        this.glasses = glasses;
    }
}

我们来看看作者举的一个正面的例子

    // BigInteger构造方法 这个方法可能会返回素数 语义表达不明确
    public BigInteger(int bitLength, int certainty, Random rnd) {
        BigInteger prime;

        if (bitLength < 2)
            throw new ArithmeticException("bitLength < 2");
        prime = (bitLength < SMALL_PRIME_THRESHOLD
                                ? smallPrime(bitLength, certainty, rnd)
                                : largePrime(bitLength, certainty, rnd));
        signum = 1;
        mag = prime.mag;
    }
  
    //所以在最后BigInteger 提供了一个静态方法 这个方法名清晰的告诉了我们可能是返回素数的
    public static BigInteger probablePrime(int bitLength, Random rnd) {
        if (bitLength < 2)
            throw new ArithmeticException("bitLength < 2");

        return (bitLength < SMALL_PRIME_THRESHOLD ?
                smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) :
                largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd));
    }

静态工厂方法与构造器不同的第二大优势在于,不必在每次调用它们的时候都创建一个新的对象

我们知道既然你调用了构造方法那肯定是会新建一个对象的,但是用静态工厂方法就不一定了,我们可以先将对象缓存起来

这个例子是Boolean类的

    public static final Boolean TRUE = new Boolean(true);

    public static final Boolean FALSE = new Boolean(false);

    // 直接返回了保存好的对象
    public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }

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

RegularEnumSet 和 JumboEnumSet 全部都是继承自EnumSet

   public static > EnumSet noneOf(Class elementType) {
       Enum[] universe = getUniverse(elementType);
       if (universe == null)
           throw new ClassCastException(elementType + " not an enum");
       // 返回一个EnumSet子类
       if (universe.length <= 64)
           return new RegularEnumSet<>(elementType, universe);
       else
           return new JumboEnumSet<>(elementType, universe);
   }

本段落还有一个例子, 现在我并没有看懂,也并没有懂适配器模式,所有以后再来补充

静态工厂第四大优在于,在创建参数化类型实例的时候,它们使代码变得更加简洁

这一点现在已经不存在了,但还是举个例子

    // java1.7以前 即使泛型已经规定好了数据类型,但是你还是要写出来
    List  list = new ArrayList();

    // java1.7以后
    List list = new ArrayList<>();

    // Guava Lists静态工厂方法 
    public static  ArrayList newArrayList(E... elements) {
        checkNotNull(elements); 
        int capacity = computeArrayListCapacity(elements.length);
        ArrayList list = new ArrayList<>(capacity);
        Collections.addAll(list, elements);
        return list;
    }

    //调用 通过静态方法工厂就不需要写出来了
    List list = Lists.newArrayList("1");

静态工厂方法的主要缺点在于,类如果不含公有的或者受保护的构造器,就不能被子类化

如果构造器为私有的,通过静态方法来获得对象,那么该类是没有办法子类化的,也就是说无法继承.

静态工厂方法的第二个缺点在于,它们与其他的静态方法实际上没有任何区 别

本质上还是一个静态方法,但是实质上它用于创建对象,和普通静态方法差别很大,却没有有效的办法可以区分他们

作者的建议: 在类或接口注释中关注静态工厂,给静态工厂方法命名时遵守惯用的命名规范.

总结

简而言之,静态工厂方法和公有构造器都各有用处,我们需要理解它们各自的长处,静态工厂通常更加合适,因此切忌第一反应就是提供公有的构造器,而不先考虑静态工厂

你可能感兴趣的:(1.考虑用静态工厂方法代替构造器)