一、考虑使用静态工厂方法替代构造函数

1、何为静态工厂方法

  静态工厂方法就是一个返回类实例的静态方法。比如Boolean的valueof方法:

1 public static final Boolean TRUE = new Boolean(true);
2 public static final Boolean FALSE = new Boolean(false);
3
4 public static Boolean valueOf(boolean b) {
5     return (b ? TRUE : FALSE);
6 }

2、为什么使用静态工厂方法

  和公共构造函数相比,静态工厂方法有许多的优点,下面进行一一介绍:

  (1)静态工厂方法是有名字的

    一个类的构造函数的名字都是相同的,为了区分两个不同的构造函数,只能通过参数类型的顺序或个数,这样,在没有阅读参考类文档的情况下,使用者很可能会错误的调用构造方法。

    而静态工厂方法不同,如果有一个精心选择的方法名称,那么就不会存在上面说的问题,便于程序的阅读和理解。

    例如,返回一个可能为素数的方法,在未查看文档的情况下,静态工厂方法比构造函数更容易理解:

 1 // 构造方法
 2 public BigInteger(int bitLength, int certainty, Random rnd) {
 3     BigInteger prime;
 4
 5     if (bitLength < 2)
 6         throw new ArithmeticException("bitLength < 2");
 7     prime = (bitLength < SMALL_PRIME_THRESHOLD
 8                     ? smallPrime(bitLength, certainty, rnd)
 9                     : largePrime(bitLength, certainty, rnd));
10     signum = 1;
11     mag = prime.mag;
12 }
13
14
15 // 静态工厂方法
16 public static BigInteger probablePrime(int bitLength, Random rnd) {
17     if (bitLength < 2)
18         throw new ArithmeticException("bitLength < 2");
19
20     return (bitLength < SMALL_PRIME_THRESHOLD ?
21             smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) :
22             largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd));
23 }        

  (2)静态工厂方法不用每次调用时候都创建一个新的对象

    静态工厂方法可以在任何时候对存在类的实例进行控制,在重复调用的时候返回相同的对象,避免创建不必要的重复对象。这样做可以极大的提高程序的性能,尤其是对那些创建成本非常高的类。比如在Boolean类的valueof方法中,它返回的是预先定义的对象,而这2个对象是静态不可变的,所以无论在何时调用这个方法,都会返回相同的对象,而不是重新创建对象。

  (3)静态工厂方法可以返回其子类型对象

    这样为选择返回对象提供了很大的灵活性。如java.util.EnumSet类,可以返回EnumSet的子类。

  (4)静态工厂方法可以根据输入参数的不同返回不同的类

    返回类型的任何子类都是可以的,返回对象的类可以根据参数不同而发生变化。

    比如java.util.EnumSet,其本身被abstract修饰,无法直接调用其构造函数。但可以调用其静态方法noneOf来创建对象,并且根据参数返回合适的对象:

 1 public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
 2     Enum<?>[] universe = getUniverse(elementType);
 3     if (universe == null)
 4         throw new ClassCastException(elementType + " not an enum");
 5
 6     if (universe.length <= 64)
 7         return new RegularEnumSet<>(elementType, universe);
 8     else
 9         return new JumboEnumSet<>(elementType, universe);
10 }

    方法返回的2个类的存在对客户端来讲是不可见的,如果在未来版本中淘汰其中1个实例,不会造成任何的影响;同时,添加第三或第四个实现,也不会存在问题。

  (5)静态工厂方法在编写包含该方法的类时,返回对象的类可以不存在

    这构成了服务提供者框架的基础,如jdbc的API。服务提供者框架是提供者实现服务的系统,并且系统使得实现对客户端可用,从而将客户端从实现中分离出来。

    服务提供者框架基本组成:

    ① 服务接口:基本组件,表示实现;

    ② 提供者注册API:基本组件,提供者用来注册实现;

    ③ 服务访问API:基本组件,客户端使用该API获取服务的实例;允许客户指定选择实现的标准,在缺乏标准的情况下,API返回一个默认实现的实例,或者允许客户通过所有可用的实例进行遍历;

    ④ 服务提供者接口:可选组件,描述一个生成服务接口实例的工厂对象。

3、静态工厂方法的缺点

  (1)没有公共或者被保护的构造方法的类不能被子类化

    如果我们在类中,将构造方法设置为private,只提供静态工厂方法来构建对象,那么我们将不能通过继承来扩展该类。

    但是这也会鼓励我们使用组合而不是继承,并且是不可变类。

  (2)程序员很难找到静态工厂方法

    静态工厂方法不像构造方法那样在API文档中显得很突出,这样找到他们就变的非常困难。这样,我们只能通过将注意力引到类或接口文档中的静态方法以及通用的命名约定来减少这个问题。

    静态工厂方法的常用名称有:

    • from:接收单个参数并返回此类型的相应实例,如Date d = Date.from(instant);
    • of:接收多个参数并返回该类型的实例,并把他们合并在一起,如Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
    • valueof:from和of更为详细的替代方式,如BigInteger prime = BigInteger.valueof(Integer.MAX_VALUE);
    • instance或者getInstance:返回一个由其参数描述的实例,返回的实例可能拥有相同的值,如StackWalker luke = StackWalker.getInstance(options);
    • create或者newInstance:和instance或者getInstance类似,不同的是该方法保证每一个调用都返回一个新的实例,如Object newArray = Array.newInstance(classObject, arrayLen);
    • newType:和newInstance类似,但只有在工厂方法在不同类中时,才使用该方法,如BufferedReader br = Files.newBufferedReader(path);
    • type:getType和newType简洁的替代方式。

总之,静态工厂方法和构造函数都有各自的用途,但通常静态工厂方法是更可取的,所以应该避免在未考虑使用静态工厂方法的基础上就直接使用公共构造方法。      

原文地址:https://www.cnblogs.com/origalom/p/9537857.html

时间: 2024-08-06 11:06:23

一、考虑使用静态工厂方法替代构造函数的相关文章

考虑用静态工厂方法替代构造器的情况

考虑用静态工厂方法替代构造器 原来创建一个自定义类的实例最常用的方法是采用构造器,但一个类可以有多个构造器,而所有的构造器名字都相同,我们只能通过参数来区分不同构造器的作用.除了采用构造器外,还可以采用静态工厂方法,该方法返回类的实例便可,自定义的方法可以自己命名,这样一来就很容易区分每个方法的作用了. 例子: publicclass CreateObject { intage; String name; public CreateObject(String name){ this.name =

考虑使用静态工厂方法替代构造方法

创建对象 构造方法创建对象 在Java中,创建对象常用的方法是通过公有构造方法创建: 举个例子:如下,是Boolean类的一个构造方法,以及通过该构造方法创建一个Boolean对象: public Boolean(String s) { this(toBoolean(s)); } Boolean bTrue = new Boolean("true"); 静态工厂方法创建对象 其实,创建对象还有另外一种方法,通过公有静态工厂方法来创建对象,不过这种方法往往容易被程序员忽略: 举个例子,如

java的设计模式 - 静态工厂方法

静态工厂方法,也不知道为何叫这个名字.其实也就是一个静态函数,可以替代构造函数用.大名鼎鼎的 guava 就大量使用这种模式,这是非常有用的模式. 比如是 Integer i = Integer.valueOf(123); Boolean bool = Boolean.valueOf(true); //guava 的方法 ConcurrentMap<String,Integer> concurrentMap = Maps.newConcurrentMap(); ArrayList<Int

静态工厂方法VS构造器

我之前已经介绍过关于构建者模式(Builder Pattern)的一些内容,它是一种很有用的模式用于实例化包含几个属性(可选的)的类,带来的好处是更容易读.写及维护客户端代码.今天,我将继续介绍对象创建技术. 在我看来,下面这个类是非常有用的例子.有一个RandomIntGenerator 类,产生随机的int类型的整数.如下所示: public class RandomIntGenerator { private final int min; private final int max; pu

创建和销毁对象——用静态工厂方法代替构造器

参考资料:<Effective Java>,https://www.jianshu.com/p/ceb5ec8f1174. 基础回顾 1.什么是构造器? 构造器与类同名,在新建一个类的对象时,构造器会运行,以便将实例初始化为所希望的状态. 每个类都会有一个默认的无参的构造器.也可以自己手动写一个构造器. 如,在People类中写一个构造器: public People(String Name,int Age) { this.Name=Name; this.Age=Age; } 然后新建一个关于

Efflective Java读书笔记 第一条 考虑用静态工厂方法代替构造器

创建一个类的实例的方法,最常用的是提供一个公有[public]的构造器,另外还有一种方法是类可以提供一个公有的静态工厂方法. 静态工厂方法对于构造器有着不同的优势和劣势. 优势: 1.静态工厂方法可定义更有意思的名称,而构造函数只能是类名. eg:BigInteger的构造函数返回的可能是素数,不过使用BigInteger.probablePrime更加明确. 2.静态工厂方法不必没有调用的时候都创建一个新的对象,这对于不可变类可以预先构造好实例,调用时静态工厂方法直接返回即可. eg:Bool

Effective Java 读书笔记(一):使用静态工厂方法代替构造器

这是Effective Java第2章提出的第一条建议: 考虑用静态工厂方法代替构造器 此处的静态工厂方法并不是设计模式,主要指static修饰的静态方法,关于static的说明可以参考之前的博文<java中final与static的使用场景总结>. 什么是静态工厂方法? 可以参考书中的例子(摘自JDK1.7 java.lang.Boolean) public final class Boolean implements java.io.Serializable, Comparable<

考虑用静态工厂方法代替构造器的场景

总结点,使用场景: a.当你尝试使用多个构造器,然后,每个构造器的区别是签名(参数类型或者参数顺序不同或者参数数量不同),那么,这个时候,可以考虑使用静态工厂方法来替代构造器.“如果构造器的参数本身没有确切地描述正被返回的对象,那么具有适当名称的静态工厂会更容易使用,产生的客户端代码也更易于阅读” Example: BigInteger.probablePrime()返回一个素数的整数 相比构造器Biginteger(int, int, Random)要直观 Car.smallCar()返回小车

【浅析】静态工厂方法

第一次看到这个名词是在Effective的第一条中,书中先是数落了一番构造器之后提出静态工厂方法的好处如何如何.看完后觉得,虽然这个名词之前没听过,其实在开发途中用的不少,入类型转换valueOf(),单例模式中的getInstance()均有静态工厂模式的痕迹.首先是不太认可书中所说的好处,于是上网寻找资料.总结如下: 一.什么是静态工厂方法 其又叫简单工厂模式,与工厂模式不同,其是通过专门定义一个类来负责创建其他类的实例,其实例通常拥有共同父类,其普遍实现主要依靠Java的反射机制. 二.好