从今天开始,固定更新一个模块,更新Effective Java这本书介绍的一些知识点。
1、考虑用静态工厂方法代替构造器
通常来说,获得一个类的实例的方法一般是使用构造器,但是也有其他方法,比如让这个类提供一个静态工厂方法,这个方法是一个生产该类实例的静态方法。
静态工厂方法比起构造器方法的优点在于:
①、有名称,这个名称可以表名这个静态工厂方法提供的实例的特点。
②、不用每次调用都创建一个对象。构造器在调用的时候总会创建一个新的对象,然而创建对象在java中是有一定的开销的,使用静态工厂方法可以解决问题。静态工厂方法不一定要在这个方法内部创建新的对象,可以是先创建好对象然后通过这个工厂返回。而且静态工厂方法能供重复调用返回相同的对象,这样有助于严格控制哪个时刻哪些类应该存在。
③、可以返回原返回类型的任何子类型的对象,更灵活。
④、代码更简洁。比如对于使用构造器来进行构造:
HashMap<String,List<String>> map = new HashMap<String,List<String>>();//这样很繁杂
然而当使用静态工厂方法的时候,可以简化以上的代码:
HashMap<String,List<String>> map = HashMap.newInstance();//更简洁 当然jdk中没有这么写
静态工厂方法的主要缺点在于:
①、如果类不含有受保护的或者共有的构造函数,则它不能被子类化。这是它的一个主要缺点,但是也可以被视为优点,因为这个机制鼓励程序员不要去继承(extends)(is a),而是去复合(composition)(has a)。
②、静态工厂方法和其他静态方法没有什么表现上的差异,而不像构造器那样展现得不同。
下面用代码来展示出静态工厂方法,首先创建一个package 静态工厂,创建一个接口Provider,声明创建实例Service的方法newInstance:
package 静态工厂;
public interface Provider {
public Service newInstance();//创建实例Service的工厂
}
然后创建一个接口Service,声明被创建实例所拥有的方法:
package 静态工厂;
public interface Service {
//工厂生产实体的功能
public void run();
}
创建Services类,用来提供对应工厂生产的对应实例:
package 静态工厂;
import java.util.concurrent.ConcurrentHashMap;
public class Services {
//Services工厂中名字和生产实例的类的实例映射
private final static ConcurrentHashMap<String,Provider> map = new ConcurrentHashMap<String,Provider>();
private final static String DEFAULT_NAME = "default";
//提供注册工厂的函数
public static void RegisterProviders(String name , Provider p){
map.put(name, p);//添加工厂对应的名字及工厂实例
}
public static void RegisterDefaultProviders(Provider p){
RegisterProviders(DEFAULT_NAME, p);
}
//生产实例
public static Service newInstance(String name){
Provider p =map.get(name);//不是newInstance的时候才创建 而是实现创建好存储在map里
if(p == null){
throw new IllegalArgumentException("没有这样的工厂:"+name);
}
return p.newInstance();
}
}
然后定义一个Provides类定义所需要的所有工厂类型:
package 静态工厂;
public class Providers {
public static final Provider p1 = new Provider(){
@Override
public Service newInstance() {
return new Service(){//返回匿名实例
@Override
public void run() {
System.out.println("This is service of P1");
}
};
}
};
public static final Provider p2 = new Provider(){
@Override
public Service newInstance() {
return new Service(){
@Override
public void run() {
System.out.println("This is service of P2");
}
};
}
};
}
最后写一个测试类,来测试工厂:
package 静态工厂;
public class Test {
public static void main(String[] args) {
//获取生产者
Provider p1 = Providers.p1;
Provider p2 = Providers.p2;
//注册工厂
Services.RegisterProviders("provider1",p1);
Services.RegisterProviders("provider2",p2);
//获取实例
try {
Service s1 = Services.newInstance("provider1");
Service s2 = Services.newInstance("provider2");
s1.run();
s2.run();
} catch (Exception e) {
e.printStackTrace();
}
}
}
在需要创建实例的时候,静态工厂方法通常更加合适,因此切忌第一个感觉就是使用构造器,而不是静态工厂方法。