effective java 之使用静态工厂方法替代构造方法

effective java 之使用静态工厂方法替代构造方法


1、用构造方法创建对象:

在Java中,创建对象常用的方法是通过公有构造方法创建;

Boolean bTrue = new Boolean("true");

public Boolean(String s) {
this(toBoolean(s));
}

2、静态工厂方法创建对象:

创建对象还有另外一种方法,通过公有静态工厂方法来创建对象。
如下是Boolean类的valueOf方法,以及通过该静态工厂方法返回的Boolean实例,注意,这里并没有创建Boolean实例对象,而是返回事先创建好的Boolean对象;

public static Boolean valueOf(String s) {
return toBoolean(s) ? TRUE : FALSE;
}

Boolean bTrue = Boolean.valueOf("true");

3、Boolean类源码:

public final class Boolean implements Serializable, Comparable
{
public Boolean(boolean flag)
{
value = flag;
}
//构造器
public Boolean(String s)
{
this(toBoolean(s));
}


public static boolean parseBoolean(String s)
{
return toBoolean(s);
}
public boolean booleanValue()
{
return value;
}

public static Boolean valueOf(boolean flag)
{
return flag ? TRUE : FALSE;
}
//静态工厂
public static Boolean valueOf(String s)
{
return toBoolean(s) ? TRUE : FALSE;
}

public static String toString(boolean flag)
{
return flag ? "true" : "false";
}

public String toString()
{
return value ? "true" : "false";
}

public int hashCode()
{
return value ? 1231 : '\u04D5';
}

public boolean equals(Object obj)
{
if(obj instanceof Boolean)
return value == ((Boolean)obj).booleanValue();
else
return false;
}

public static boolean getBoolean(String s)
{
boolean flag = false;
try
{
flag = toBoolean(System.getProperty(s));
}
catch(IllegalArgumentException illegalargumentexception) { }
catch(NullPointerException nullpointerexception) { }
return flag;
}

public int compareTo(Boolean boolean1)
{
return compare(value, boolean1.value);
}

public static int compare(boolean flag, boolean flag1)
{
return flag != flag1 ? flag ? 1 : -1 : 0;
}

private static boolean toBoolean(String s)
{
return s != null && s.equalsIgnoreCase("true");
}

public volatile int compareTo(Object obj)
{
return compareTo((Boolean)obj);
}

public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
public static final Class TYPE = Class.getPrimitiveClass("boolean");
private final boolean value;
private static final long serialVersionUID = -3665804199014368530L;
}


4、 测试类

// 在JDK提供的类中通过构造方法创建对象的方式
Boolean boolean1 = new Boolean(true);
Boolean boolean2 = new Boolean(false);
System.out.println(boolean1);
System.out.println(boolean2);

// 通过静态工厂实例化类,可以点进去查看Boolean类源码
Boolean boolean3 = Boolean.valueOf(true);
System.out.println(boolean3);

// 实体类构造方法实例化类
Person p1 = new Person("tom", 12);
System.out.println(p1.toString());
//通过静态工厂
Person p2=Person.getInstance("tom", 12);
System.out.println(p2.toString());

5、区分静态工厂方法和工厂方法模式

静态工厂方法通常指的是某个类里的静态方法,通过调用该静态方法可以得到属于该类的一个实例;

工厂方法模式是一种设计模式,指的是让具体的工厂对象负责生产具体的产品对象,这里涉及多种工厂(类),多种对象(类),如内存工厂生产内存对象,CPU工厂生产CPU对象;

简单工厂模式里的静态工厂方法会创建各种不同的对象(不同类的实例),而静态工厂方法一般只创建属于该类的一个实例(包括子类);

6、使用静态工厂方法的优势:

1、可读性更强(它们有名称)

假设我们需要写一个产生随即数的类RandomIntGenerator,该类有两个成员属性:最小值min和最大值max,
假设我们的需求是需要创建三种类型的RandomIntGenerator对象,
1、大于min,小于max;
2、大于min 小于Integer.MAX_VALUE;
3、大于Integer.MIN_VALUE 小于max


如果我们不使用静态工厂方法,代码一般如下设计:(构造方法多态性)


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;
}


//    报错:Duplicate method RandomIntGenerator(int) in type RandomIntGenerator
//    /**
//     * 大于Integer.MIN_VALUE 小于max
//     */
//    public RandomIntGenerator(int max)
//    {
//        this.max = max;
//    }
}


实例化:(可读性差,不看注释很难知道其创建的对象的具体含义)
RandomIntGenerator r1 = new RandomIntGenerator(1, 10);
RandomIntGenerator r2 = new RandomIntGenerator(10);

我们发现,以上代码不仅可读性差,而且在设计最后一个构造方法的时候,还报错,因为已经存在一个参数一致的工作方法了,提示重复定义;
那么假设我们使用静态工厂方法会怎样呢,如下所示:


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 小于max
*/
public static RandomIntGenerator between(int min, int max)
{
return new RandomIntGenerator(min, max);
}
/**
* 大于min 小于Integer.MAX_VALUE
*/
public static RandomIntGenerator biggerThan(int min)
{
return new RandomIntGenerator(min, Integer.MAX_VALUE);
}
/**
* 大于Integer.MIN_VALUE 小于max
*/
public static RandomIntGenerator smallerThan(int max)
{
return new RandomIntGenerator(Integer.MIN_VALUE, max);
}
}

实例化:
RandomIntGenerator r1 = RandomIntGenerator.between(10, 100);
RandomIntGenerator r2 = RandomIntGenerator.biggerThan(10);
RandomIntGenerator r3 = RandomIntGenerator.smallerThan(100);
成功满足需求:创建三种类型的RandomIntGenerator对象,而且创建对象的时候,代码可读性比使用构造方法强;

2、调用的时候,不需要每次都创建一个新对象(适用于单例模式)

JDK中的Boolean类的valueOf方法可以很好的印证这个优势,在Boolean类中,有两个事先创建好的Boolean对象(True,False)

public static final Boolean TRUE = new Boolean(true);
    public static final Boolean FALSE = new Boolean(false);


当我们调用Boolean.valueOf("true")方法时,返回的就是这两个实例的引用,这样可以避免创建不必要的对象,如果使用构造器的话,就达不到这种效果了;

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();
}
}

5、构成基于接口的框架:(类似于dubbo)
静态工厂方法返回对象所属的类可以是后来动态添加的。

服务提供者框架将用户和服务提供商通过几个API分离开来,有较好的扩展性。



7、使用静态工厂方法的缺点

1、如果类不含public或protect的构造方法,将不能被继承;

class MyMap<K,V> {
private MyMap()
{
}
public static <K,V> MyMap<K,V> newInstance(){
return new MyMap<K, V>();
}
}

2、与其它普通静态方法没有区别,没有明确的标识一个静态方法用于实例化类

所以,一般一个静态工厂方法需要有详细的注释,遵守标准的命名,
如使用getInstance、valueOf、newInstance等方法名;


本文参考资料
@Author      风一样的码农
@HomePageUrl http://www.cnblogs.com/chenpi/ 

effective java


通过此讲解,相信对Java有了更深一步的认识。

每天努力一点,每天都在进步。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

powerfuler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值