EffectiveJava--第一条:用静态工厂方法代替构造器

EffectiveJava–第一条:用静态工厂方法代替构造器

在我们日常的开发当中,我们经常会接触到各种各样的POJO。并且在我们使用的过程中,我们每当需要使用这个对象的时候,第一时间想到的就是new一个出来。其实,除了new,我们还可以采用其他的方法,来获取这个POJO对象,那就是-静态工厂方法

注意:在这里,我们要注意一点,不是说我们的构造方法不能用。而是说,在一些情况下,我们采用静态工厂方法会比直接采用构造器的方式,让我们的代码更加的简洁,更加容易让人理解。

那么你可能会问,什么是静态工厂方法呢?其实,在我们日常的使用中,我们已经在经常的使用了。例如,我们有一个boolean类型的变量,希望可以获取到这个变量的一个包装类,那么对于你而言,你可能第一时间想到的是Boolean.valueOf(boolean b)这个方法,通过这个方法,我们就可以获得一个对应的Boolean类型的变量了。

但是,你是否想过,JDK的库工程师们,在valueOf这个方法中,到底做了什么?是怎么把一个boolean变成Boolean类型的?接下来,我们看下JDK的库源码:

public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }

看到这里,你可能明白点了什么,但是你可能会继续问?那为什么不在valueOf方法的内部给我们new一个出来呢?要解答这个问题,我们可以接着看TRUEFALSE的源码。

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

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

看到这里,我们发现,在class加载的时候,就一个创建了两个对象TRUEFALSE。而我们每次通过valueOf获取对应包装类的时候,其实都是获取的这两个对象。这么做的好处之一是可以节省内存,同时降低内存中重复类的数量。那么我们在日常开发中,采用静态工厂方法有哪些利弊呢?

优点

优点一:有名称

说到这里,你可能觉得,这个很简单。的确,Boolean.valueOf(boolean b)的确是我们经常采用的一种方式,来产生Boolean包装类的方法。那么你有没有想过,我们为什么要采用valueOf的方式,而不是采用new Boolean(true)的方式呢?的确,对于懂的人而言,都知道无论这两种方式中的那一种,都可以给我们返回一个对应值的包装类型。但是如果我们单单从方法名称上看,new Boolean(true)我们仅仅只是创建了一个对象,那么在Boolean中的构造函数里面有什么隐藏的含义,你其实是不确定的。但是通过Boolean.valueOf(boolean b)我们可以知道,这个方法的目的就是把我们的基本类型转换成一个包装类型。起到了见名知意的作用。

优点二:不必再每次调用他们的时候都创建一个新对象

还是以Boolean这个类为例,我们都知道,当我们通过new Boolean(true)的时候,每次都会创建一个对象出来的。但是通过上面的valueOf方法。我们发现,在源码中使用了一个三目运算符。对于运算的结果,仅仅只是返回了两个常量。无论我们调用多少次,其实每次返回的都是同一个对象。

优点三:他们可以返回原返回类型的任何子类型对象

对于这个优势,其实我们可以看下JDK1.8中的源码关于Collections这个类的部分方法。在这里,我们先贴出相关的源码,在进行分析:

public static <T> Set<T> unmodifiableSet(Set<? extends T> s) {
    return new UnmodifiableSet<>(s);
}

static class UnmodifiableSet<E> extends UnmodifiableCollection<E>
                                implements Set<E>, Serializable {
    private static final long serialVersionUID = -9215047833775013803L;

    UnmodifiableSet(Set<? extends E> s)     {super(s);}
    public boolean equals(Object o) {return o == this || c.equals(o);}
    public int hashCode()           {return c.hashCode();}
}

在这里,我们先不来讨论这个方法是用来干什么的。我们仅仅只是通过方法的入参、返回值和方法内代码进行分析。首先我们发现,对于方法的入参和返回值都是一个关于Set的泛型。而在代码的内部,我们对于方法的处理,采用的是一个UnmodifiableSet类。

而通过这个类的源码我们可以知道,这个类是Set的一个子类而已。并且这个类是包级私有的。因此,对于我们而言,我们调用unmodifiableSet的方法时,并不需要了解UnmodifiableSet这个类,甚至都不需要这个类的存在。这也正是静态工厂方法的一个优点所在,它可以在方法的内部,对于数据进行包装、处理,并且可以抽象在子类的里面。而我们接收的时候,依然可以采用父类进行接收,这样不仅在降低代码复杂度的同时,同时我们还可以将细节隐藏,伴随着,我们的Doc文档也会整洁很多。

优点四:所返回的对象的类可以随着每次调用而发生变化,这都取决于静态工厂方法的参数值

这个依然可以通过valueOf方法进行讲解。在我们的入参是true的时候,此时返回的是Boolean.TRUE;当我们的入参是false的时候,此时返回的是Boolean.FALSE

优点五:方法返回的对象所属的类,在编写包含该静态工厂方法的类时可以不存在。

在这里,可能很多人理解起来都十分的困难。但是如果举个例子,会很好的理解。假如我们程序有个这样的场景。需要保存我们的数据。而数据的保存在不同的阶段可以有不同的保存形式。例如,最开始的时候,我们直接采用IO流的形式,将数据保存在文件上。后来随着数据的越来越多和检索的需求,此时我们需要将数据保存在数据库中。在这里,我们发现,我们的程序仅仅只是保存数据的方式不同。但是其他都是相同的。在这里,我们可以把数据保存这个方法抽象出来。而文件形式、数据库形式的不同的实现,可以实现这个抽象的方法就可以了。其实,优点五讲的就是这个例子。而书中所讲的服务提供者框架也是在说这个问题。

缺点

缺点一:类如果不含公有的或者受保护的构造器,就不能被子类化。

通过字面意思,我们就可以知道,对于一个类而言,如果没有公有的或者受保护的构造器,就不能被子类化。

缺点二:程序员很难发现他们。

对于这个很好理解。因为当我们在使用的时候,都是使用的是我们最常使用的API。对于这个类的其他的方法,只有在我们需要的时候,或者我们去读API的时候,才会发现。

总结

其实,如果只是单纯的读《Effective Java》这本书的话,真的是一头雾水,写的太晦涩了。以用静态工厂方法代替构造器这个为例,我们其实真的需要掌握的就是–尽可能的让我们的代码更加的易读,减轻读代码的压力。当一个构造函数有多重含义的时候,此时我们通过静态工厂方法来代替构造器能更好的让别人理解。


转载请注明来源,欢迎指出任何有错误或不够清晰的表达。可以邮件至 gouqiangshen@126.com

文章标题:EffectiveJava--第一条:用静态工厂方法代替构造器

文章字数:2k

本文作者:BiggerShen

发布时间:2019-11-22, 20:47:02

最后更新:2024-01-16, 03:51:15

原始链接:https://shengouqiang.cn/EffectiveJava/EffectiveJavaLearnDay01/

版权声明: 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏