创建和销毁对象 第一条:考虑用静态工厂方法代替构造器

来源:互联网 发布:田馥甄整容了吗 知乎 编辑:程序博客网 时间:2024/06/07 02:38

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


对于一个类而言,让客户端获取它自身的一个实例,最常用的方法就是提供一个公有的构造器. 还有一种方法,类可以提供一个公有的静态工厂方法,它是一个返回类的实例的静态方法.示例:

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

注意:静态工厂方法与设计模式中的工厂方法模式不同,本条目中所指的静态工厂方法并不直接对应于设计模式中的工厂方法.


一.类通过静态工厂方法而不是构造器来提供它的客户端,这样做的优势

  • 静态工厂方法与构造器不同的第一大优势在于,他们有名称.
    一个类只能有一个带有指定签名的构造器.开发人员通过提供多个重载构造器来避免这一问题.但是这并不是个好主意,面对这样的API,用户永远也记不住该用哪个构造器,结果常常会调用错误的构造器,并且读到使用了这些构造器的代码时,如果没有API文档,往往不知所云.
    由于静态工厂方法由名称,所以他们不受上述的限制.当一个类需要多个带有相同签名的构造器时,就用静态工厂方法替代构造器,并且慎重的选择名称以突出他们之间的区别.


    例如:在Excutors类中的静态工厂方法,newCacheThreadPool(..),newFixedThreadPool(..)..等等,通过名称我们就可以调用重载构造器,并且”见名知意”.

  • 静态工厂方法与构造器不同的第二大优势在于:不必在每次调用他们的时候都创建一个新的对象.
    这使得不可变类可以使用预先构造好的实例,或者将构建好的实例缓存起来,进行重复利用,从而避免创建不必要的重复对象. 如果程序经常请求创建对象,并且创建对象的代价很高,这项技术可以极大地提升性能.
    静态工厂方法能够为重复的调用返回相同对象,这样有助于类总能严格控制在某个时刻哪些实例应该存在(实例受控的类).这样可以确保他是一个Singleton或者是不可实例化的.


    eg:在单例类中的getInstance(Context context)方法.

  • 静态工厂方法与构造器不同的第三大优势在于:它们可以返回原返回类型的任何子类型的对象.
    这样我们在选择返回对象的类时就有个更大的灵活性.这种灵活性的应用是,API可以返回对象,同时又不会使对象的类变成公有的,以这种方式隐藏实现类会使API变得非常简洁.这项技术适用于接口的框架,因为在这种框架中,接口的静态工厂方法提供了自然返回类型.接口不能有静态方法,因此按照惯例,接口Type的静态工厂方法被放在一个名为Types的不可实例化的类中.
    例如,Java Collection Framework的集合接口有32个便利实现,分别提供了不可修改的集合,同步集合等等.几乎所有这些实现都通过静态工厂方法放在一个不可实例化的类 java.util.Collections中导出.
    静态工厂方法返回的对象所属的类,在编写包含该静态工厂方法的类时,可以不必存在.这种灵活的静态工厂方法构成了服务提供者框架.的基础.例如JDBC API.服务提供者框架是指这样的一个系统:多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从多个实现中解耦出来.


    eg:Collection框架中的Collections类,Excutor框架中的Excutors类所提供的静态工厂方法,可以提供原返回类型的子类型对象.

  • 静态工厂方法与构造器不同的第四大优势在于:在创建参数化类型实例的时候,它们使代码变得更加简单.
    eg:在调用参数化类的构造器时,即使类型参数非常明显,但是也必须要指明,这通常要求你链接两次提供类型参数:

Map<String,List<String>>m=new HashMap<String,List<String>>();

随着参数类型变长,越来越复杂,但是有了静态工厂方法,编译器就可以替你找到类型参数,这被称作类型推导(type inference),例如,假设HashMap提供了这个静态工厂:

public static <k,v> HashMap<K,V> newInstance(){    return new HashMap<k,v>();}

就可以使用下面这段代码替代上述繁琐的代码:

Map<String,List<String>>m=HashMap.newInstance();

到发行版本1.6为止,标准的集合实现如HashMap并没有工厂方法,但是可以把这些方法放到自己的工具类中.更重要的是,可以把这样的静态工厂方法放在自己的参数化类中.


二.缺点

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

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


三.静态工厂方法的惯用名称

  • valueOf——不太严格的讲,该方法返回的实例与它的参数具有相同发值,这样的静态工厂方法实际上是类型转换的方法.

  • of——valueOf的一种更为简洁的替代.在EnumSet中流行起来.

  • getInstance——返回的实例是通过方法的参数来描述的,但是不能够说与参数具有相同的值.对于Singleton来说,该方法没有参数,并返回唯一的实例.

  • newInstance——像getInstance一样,但是newInstance能够确保返回的每一个实例与所有其他实例不同.

  • getType——像getInstance一样,但是在工厂方法处于不同类中的时候使用.Type表示工厂方法所返回的对象类型.

  • newType——想newInstance一样,但是在工厂方法处于不同类中的时候使用.Type表示工厂方法所返回的对象类型.

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

0 0