采用静态工厂方法替代构造器

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

静态工厂方法是一个编程设计思想,在不同的情况下其实现方式不同,总结其不同情况下的优缺点共如下几条:

  • 优点:
    • 静态工厂方法有自己的名称,不必像构造器那样必须与类名保持一致
    • 构造器每次调用都要new一个新对象,而静态工厂方法每次被调用的时候,是否会创建一个新的对象完全取决于方法的实现
    • 可以返回当前类的子类的实例,在创建松耦合的系统接口框架时发挥作用(接口编程,Collection结合框架是个很好的例子)
    • 在创建参数化类型实例的时候,可以使代码更加简洁
  • 缺点:
    • 类如果不含有公有或受保护的构造器,就不能被子类化
    • 静态工厂方法与其他一般的静态方法并没有什么本质上的区别,它们在API文档并没有明确指出,这会造成如何查明实例化一个类是相当麻烦的

优点一 :静态工厂方法有自己的名称,不必像构造器那样必须与类名保持一致

静态工厂方法可以突破构造函数不能自由命名的限制,对于不同的工厂方法可以采用不同的会意的名字,是程序具有更好的可读性。JAVA平台库的java.text.Format的子类NumberFormat就有getInstance() , getPrecentInstance() , getCurrencyInstatnce()等静态方法,通过不同的名字产生特定的对象。


优点二:不必像构造器调用那样每次都要new一个新对象

静态工厂方法能够为重复的调用返回相同的类型,这种类被称为实例受控的类(instance-controlled),如singleton、不可实例化的类。如果程序经常请求创建相同的对象,并且创建对象的代价很高,这项技术可以极大地提升性能。

public class Boolean(){ 
    public static final Boolean True = new Boolean(true);//final就限定了TRUE对象是此Boolean实例的singleton对象
    public static final Boolean FALSE = new Boolean(false);
    public static Boolean valueOf(boolean b){
    return (b?TRUE:FALSE); 
    }
}

优点三:可以返回当前类的子类的实例,在创建松耦合的系统接口框架时发挥作用(面向接口编程)

我们在选择返回对象的类时有了更大的灵活性。它把底层的具体实现方式全部封装,编程人员只需通过接口来引用被返回的对象,而不是通过它的实现类来引用被返回的对象,这样在以后增添或删除某个具体实例子类不会对任何现有的实现方式造成什么影响。
另外采取接口编程时(class反射动态加载),不会因为其某个具体实现类出错从而导致整个功能接口都无法使用。比如Office接口是整个办公接口,word、excel是其具体实现类,如果excel出错,但是word仍可以使用。

class c = Class.forName("word");
Office oa = (Office) c.newInstance();

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

public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
    implements Cloneable, java.io.Serializable {
    EnumSet(Class<E>elementType, Enum[] universe) {
    }
    //RegularEnumSet与JumboEnumSet均为EnumSet的子类
    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
        if (universe.length <= 64)
            return new RegularEnumSet<>(elementType, universe);
        else
            return new JumboEnumSet<>(elementType, universe);
    }
}

优点四:在创建参数化类型实例的时候,可以使代码更加简洁

在调用参数化类的构造器时,即使类型参数很明显,也必须指明。这通常要求接连两次提供类型参数。比如下述实例中,类型参数

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

如有了静态工厂方法,编译器就可以替你找到类型参数。这被称作类型推导(type inference)。
例如,假设MyHashMap提供了下面这样的静态工厂方法:

    //静态工厂方法
    public static <K, V> MyHashMap<K, V> newInstance()
    {
        return new MyHashMap<K, V>();
    }
那么就

可以用下面这句简洁的代码替代上面繁琐的声明:

Map<String,List<String>> m2=MyHashMap.newInstance();

缺点的解决方法:

我们可以通过遵循静态工厂方法的命名规范来弥补这一劣势,下面是静态工厂方法的一些惯用名称:

  • valueOf - 返回的实例与它的参数具有相同的值,一般作为类型转换使用,例如Boolean.valueOf(boolean)

  • getInstance - 返回的实例通过方法的参数来描述,但不能说与参数具有同样的值。对于Singleton来说,使用无参getInstance,返回唯一的实例。

  • newInstance - 像getInstance一样,但其能够确保每次都返回新的对象。

  • getType - 像getInstance一样,但此方法返回的对象是另一个不同的类。

  • newType - 像getType一样,但每次返回一个新对象。

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页