使用静态工厂的优势

1.  不同于构造函数,可以赋予静态工厂更有意义的名字


        eg. BigInteger的构造方法BigInteger(int, int, Random)返回一个可能为质数的BigInteger,一个更好的名字是BigInteger.probablePrime(jdk在1.4中添加了此静态工厂)。


       多个具有相同签名的方法容易令人混淆,可以通过使用不同名称的静态工厂避免之。



2.  静态工厂不同于构造函数,可以在调用时不创建新的对象。


        eg.Boolean.valueOf(boolean b)。其实现接近于FlyWieght模式。valueOf返回共享的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); 
 
     }

        静态工厂可以更好的控制对象的创建过程。它可以创建单件,阻止类实例化,保证不变对象的唯一性(a.equals(b) 当且仅当 a == b)。



3.  静态工厂不同于构造函数,可以返回子类对象。


        隐藏具体实现的类型是这种灵活性的应用之一,可以有效地精简API。Interface-based frameworks就使用了此技术。由于接口不能定义提供static方法,用于创建类型Type的静态工厂按照惯例被放在一个以Types命名的不可实例化类中。例如java的collection框架除了基本的集合类之外,还提供了32个实用集合类的便捷实现,包括同步类(synchronized)和不可修改类(unmodified)等等。他们都通过不可实例化的Collections类中的静态工厂获得。

        静态工厂不仅可以返回子类对象,而且可以根据参数在不同的调用中返回不同的对象。eg.java.util.EnumSet


        无公有构造函数,只有静态工厂noneOf。如果EnumSet中的枚举类型的枚举值不超过64个,则返回RegularEnumSet(使用long实现),否则返回JumboEnumSet(使用long数组实现)。


        这样,既可以避免用户记忆过多的API,又可以将功能的实现与客户端解耦,修改甚至替换隐藏类的实现对客户端没有任何影响。


        Service provider frameworks同样利用了静态工厂的这个特点。在service provider frameworks中,被静态工厂返回的类甚至可以在静态工厂定义时不存在。例如JDBC。


        Service provider frameworks包含三个关键模块。


  • a service interface:描述服务,由服务提供者实现
  • a provider registration API:用于注册服务提供者。服务提供者被注册后,才可以被客户访问
  • a service access API:客户获取服务的方法

        可选模块a service provider interface:约定提供者创建服务的方式

        在JDBC中,Connection是一种服务,DriverManager.registerDriver是registration API,DriverManager.getConnection是access API。一个简单的service provider frameworks

4.静态工厂可以简化繁琐的泛型对象的创建

public interface Service { 
 
// service here  
 }  
 public interface Provider {  
Service getService();  
 }  
 // Noninstantiable class for service registration and access  
 public class Services {  
private ConcurrentHashMap<String, Provider> providers = new   
ConcurrentHashMap<String, Provider>();  

  public static final DEFAULT_SERVICE_NAME = “<default>”; 
 

  public registerProvider(Provider p) { 
 
registerProvider( DEFAULT_SERVICE_NAME,  p);  
}  

  public registerProvider(String name, Provider p) { 
 
providers.put(name, p);  
}  
// Service access API  
public static Service newInstance() {  
return newInstance(DEFAULT_PROVIDER_NAME);  
}  

  public static Service newInstance(String name) { 
 
Provider p = providers.get(name);  
if (p == null) {  
throw new IllegalArgumentException("No provider registered with name: " + name);  
return p.newService();  
}  
 }

        eg. 我们现在必须写Map<String, List<String>> m = new HashMap<String, List<String>>();


        如果有静态工厂


public static <K, V> HashMap<K, V> newInstance() { 
 

   return new HashMap<K, V>(); 
 

  }

        则可以这样写:Map<String, List<String>> m = HashMap.newInstance(); 我们可以在自己的util类和自定义的泛型类中加入该静态工厂。


        


静态工厂的缺点

        1. 只有静态工厂的类无法被继承。因为继承需要类中包含public或protected方法。


        2. 静态工厂不能很好的同其它静态方法区分开。API文档中不能突出它们的特殊用途。用户可能不知道如何实例化这个类。


        常用的静态工厂方法名


  • valueOf:常用于类型转换,如Boolean.valueOf
  • of:valueOf的简化版,如EnumSet.of
  • getInstance, newInstance: 前者可能不创建新的对象。
  • getType, newType : 同getInstance和newInstance。但工厂方法往往包含在其他类中。


小结:静态工厂和构造函数各有利弊,权衡后选择其一。不要急于使用构造函数,先考虑一下静态工厂。