通常情况下,我们在写一个类时,一般会赋予它一个或几个public的构造函数,让外部程序能够创建对象. 然而,在effective java 中,从另一个角度告诫我们在使用public的构造函数前,先考虑用public 的静态函数来创建对象.
其优点如下:
1. 一个静态的工厂函数,可以取不同的名字. 而构造函数的名字只能与类同名.
一个API的设计中,一个好懂的名字可以免去使用者在文档中查找其使用方法的麻烦.
如: 假如有个类叫Human,假如它有个构造函数 Human( int sex) ,根据参数来创建不同的对象. 用户就可能去查文档,sex=1 or sex=0 分别代表什么. 但如果我们给它加两个静态的工厂函数,Human.getMan() 和 Human.getWoman() 用户一看名字就知道是怎么用.
另外,正因为静态工厂函数可以取不同的名字,可以免去构造函数限定参数的烦恼.
例子同上,如我们要有一个根据身高来创建一个Human对象,于是我们写有Human(int height), 后来,我们又想根据年纪来创建一个对象,于是我们又有Human(int age), 很明显,由于函数签名的限制,我们只能选择其中一个构造函数.但使用静态工厂方法就没有这个烦恼. 我们可以有Human.getInstanceByHeight(int height) 也可以有 Human.getInstanceByAge(int age),他们可以很合谐的在一起工作.
2. 使用静态工厂函数,不必像构造函数那样每次都创建对象,可以在很大程度上节约资源,特别是有些类仅有有限个数的对象时.
如 我们有Month这么一个类, 按照原来的方法,我们可能有Month(int mon), 于是,每次调用一个构造函数,就会创建一个Month对象,其结果是内存中很可能存在大于12个Month对象. 然而,假如,我们事先定义12个静态对象,从Jan到Dec,然后给一个Month.getMonth(int mon)这么一个静态工厂方法, 在函数中根据数字返回其中一个静态对象,这样,不管程序怎么运行,内存中始终只有12个Month对象.
这样做还有一个好处就是, 用户可以直接使用== 比较两个对象是否相等,而不用equal方法.
3. 一个静态工厂函数,返回的对象可以是这个类的对象,也可以是其子类的对象,增加了设计的灵活性。在实际运用中,可以得到几个好处。
其一,可以隐藏一些类,减少对外公布的API数,精简接口。这句话可以这样理解。比如设计一个框架,里面包含有20个类,但实际上,我们可以通过使用静态工厂函数隐藏一些内部实现,使用户不用知道全部的类及使用方法,使框架易用。书中的例子是Java的集合类,实际上sun实现了多达32个集合类,包括长度不可变的,或是线程安全的等等,这些类名是隐藏的,但我们不用直接面对这些复杂类名,只需要调用静态方法就可以得到我们所需要的包含某个特性的集合类,使得这些集合方便易用。
其二,可能根据参数不同创建不同的对象。书中例子很好理解。设计了两个对外接口都一样的集合类,一个适合于小数量容量的集合,一个适合于大容量的集合。采用这种方式,用户可以不用关心什么情况下用什么类,只要将长度参数传入静态工厂函数,这个静态工厂函数就可以根据数据来判断使用哪个类而返回这个类的对象。
此外,这种方式有很好的扩展性。我们可以在写好方法后,再根据需要补充新的类。书中的例子写得很好,这里就把例子再简化一下。
public interface Service {
//这里是一个服务。
public doOperation();
}
/**
* 这个类是来产生前一个类的
*/
public interface Provider {
Service newService();
}
//这个类用来产生需要的类
public class Services {
private Services() { } //私有构造函数
// 这个东东用来存放已注册的服务类
private static final Map<String, Provider> providers = new ConcurrentHashMap<String, Provider>();
public static final String DEFAULT_PROVIDER_NAME = "Default Service"; //提供一个默认方法
// 注册默认的服务提供商
public static void registerDefaultProvider(Provider p) {
registerProvider(DEFAULT_PROVIDER_NAME, p);
}
//注册服务提供商
public static void registerProvider(String name, Provider p){
providers.put(name, p);
}
//通过这个函数获得服务对象
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(); //返回正确的对象
}
}
4. 采用静态工厂函数可以避免冗长的构造参数.
书上的例子说明的很清楚.
原来:
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();
当然,什么都是双刃剑,有利则有弊.
缺点: 1. 当使用私有构造函数后, 类不能被继承
2. 当一个类包括多个静态方法时, 静态的工厂方法不易被区分开.
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/mutsinghua/archive/2010/01/12/5183481.aspx