第01条 用静态工厂方法代替构造方法
2019-04-03 本文已影响0人
沅兮
获取类的实例
对于一个类来说,让使用着获取它自身的一个实例,最常用的方法是提供一个
公有的构造方法
。
// 以包装类Boolean为例
Boolean flag = new Boolean("true");
public Boolean(String s){
this(toBoolean(s));
}
除了公有构造方法外,我们更应该提供一个
静态工厂方法
,它只是一个返回该类实例的静态方法。
Boolean flag = Boolean.valueOf(true);
public static Boolean valueOf(boolean b){
return b ? Boolean.TRUE : Boolean.FALSE ;
}
静态工厂方法与工厂方法模式区别
-
静态工厂方法
指某个类里的静态方法,通过调用该静态方法可以得到属于该类的一个实例 -
工厂方法模式
是一种设计模式,指的是让具体的工厂对象负责生产具体的产品对象,这里涉及多种工厂(类),多种对象(类),如:内存工厂生产内存对象,CPU工厂生产CPU对象 -
简单工厂模式
里的静态工厂方法会创建各种不同的对象(不同类的实例),而静态工厂方法
一般只创建属于该类的一个实例(包括子类)
静态工厂方法的优势
优势1:可读性强,方法有名称
-
假设我们需要写一个产生随即数的类
RandomIntGenerator
,该类有两个成员属性:最小值min
和最大值max
,假设我们的需求是需要创建三种类型的RandomIntGenerator
对象,- 大于min,小于max;
- 大于min 小于Integer.MAX_VALUE;
- 大于Integer.MIN_VALUE 小于max
-
如果我们不使用静态工厂方法,代码一般如下设计:
- 同样的构造方法,不看注释不查代码就很难明白对象创建的具体含义
public class RandomIntGenerator{
// 最小值
private int min = Integer.MIN_VALUE;
// 最大值
private int max = Integer.MAX_VALUE;
// 大于min,小于max
public RandomIntGenerator(int min, int max){
this.min = min;
this.max = max;
}
// 大于min 小于Integer.MAX_VALUE
public RandomIntGenerator(int min){
this.min = min;
}
// 大于Integer.MIN_VALUE 小于max
// 报错:Duplicate method RandomIntGenerator(int) in type RandomIntGenerator
// 原因:已经存在一个参数一致的工作方法,重复定义了
public RandomIntGenerator(int max){
this.max = max;
}
}
使用静态工厂方法实现
public class RandomIntGenerator {
private int max = Integer.MAX_VALUE;
private int min = Integer.MIN_VALUE;
private RandomIntGenerator(int min, int max) {
this.min = min;
this.max = max;
}
// 通过名字就可以知道
public static RandomIntGenerator between(int min, int max) {
return new RandomIntGenerator(min, max);
}
public static RandomIntGenerator biggerThan(int min) {
return new RandomIntGenerator(min, Integer.MAX_VALUE);
}
public static RandomIntGenerator smallerThan(int max) {
return new RandomIntGenerator(Integer.MIN_VALUE, max);
}
}
优势2:调用的时候不用每次都创建新对象
- JDK中的Boolean类的valueOf方法可以很好的印证这个优势,在Boolean类中,有两个事先创建好的Boolean对象(True,False)
- 当我们调用Boolean.valueOf("true")方法时,返回的就是这两个实例的引用,这样可以避免创建不必要的对象
public final class Boolean implements Serializable,Comparable<Boolean>{
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
}
public static Boolean valueOf(String s) {
return toBoolean(s) ? TRUE : FALSE;
}
优势3:可以返回原返回类型的任何子类型对象
//RedDog和BlackDog为Dog的子类
public static Dog getInstance(){
return new RedDog();//或者return new BlackDog();
}
优势4:代码更加简洁
class MyMap<K,V> {
public MyMap(){
}
public static <K,V> MyMap<K,V> newInstance(){
return new MyMap<K, V>();
}
}
public class Main{
public static void main(String[] args){
MyMap<String, String> map1 = new MyMap<String, String>();
// 更加简洁,不需要重复指明类型参数,可以自行推导出来
MyMap<String, String> map2 = MyMap.newInstance();
}
}
使用静态工厂方法的缺点
如果类不含public或protect的构造方法,将不能被继承
// 此类因为没有public或protect的构造,故不能被继承
class MyMap<K,V> {
private MyMap(){
}
public static <K,V> MyMap<K,V> newInstance(){
return new MyMap<K, V>();
}
}
与其它普通静态方法没有区别,没有明确的标识一个静态方法用于实例化类
- 所以,一般一个静态工厂方法需要有详细的注释,遵守标准的命名,如使用getInstance、valueOf、newInstance等方法名