通常来说,要在程序中创建一个对象,第一反应就是通过类中提供的有参或无参构造器。但是并非所有场景都适合这样干,有些时候,使用静态工厂方法也许更好。例如:在创建对象的时候,需要一个带有描述的调用,然而构造器名要求必须和类名相同,所以显然无法实现这一需求,这个时候使用静态工厂方法就可以很好的实现,并且代码可读性更好。除此之外,使用静态工厂创建对象也有其他优势。
指定静态工厂方法名称,提高代码可读性
通过指定静态方法的名称,可以很直观的看到要创建什么样的对象。比如要创建一个银行对象,假设币种有人民币和美元两种,这个时候就可以分别调用不同的静态工厂方法拿到包含各个币种对应金额的银行对象。
@Data
public class Bank {
private static Bank bank;
//名称
private String name;
//币种
private String currency;
//金额
private BigDecimal money;
/**
* 创建金额为美元的对象
* @param money
* @return
*/
public static Bank getDollar(String money){
bank = new Bank();
bank.name = "奥特曼银行";
bank.currency="美元";
BigDecimal init = new BigDecimal(money);
BigDecimal price = init.multiply(new BigDecimal("6.00"));
bank.money = price;
return bank;
}
/**
* 创建金额为人民币的对象
* @param money
* @return
*/
public static Bank getRMB(String money){
bank = new Bank();
bank.name = "奥特曼银行";
bank.currency = "人民币";
BigDecimal price = new BigDecimal(money);
bank.money = price;
return bank;
}
}
创建一个类,包含两个静态工厂方法,分别创建金额为人民币的对象和金额为美元的对象。现在测试创建对象。
public class test_01 {
public static void main(String[] args) {
Bank dollar = Bank.getDollar("10");
Bank rmb = Bank.getRMB("10");
System.out.println(dollar.getName()+","+dollar.getCurrency()+","+dollar.getMoney());
System.out.println(rmb.getName()+","+rmb.getCurrency()+","+rmb.getMoney());
}
}
输出
奥特曼银行,美元,60.00
奥特曼银行,人民币,10
通过静态工厂方法,不仅可以创建针对不同属性对应结果数据的对象,还可以指定方法的名称,大大提高了对象创建的灵活性和可读性。
使用静态工厂方法创建单例对象,节省内存开销
假如现在要求Bank对象是单例的,也需要使用静态工厂去创建对象
public static Bank getBank(){
if(bank!=null){
System.out.println("返回已存在的Bank对象");
return bank;
}
bank = new Bank();
return bank;
}
提示
如果在多线程环境中,上面这个静态方法有可能创建出多个对象,现在不过多描述,因为主要是为了介绍静态工厂方法创建对象的优势。如果要求一个类的对象是单例的,则需要使用静态工厂去创建。
使用静态工厂方法还可以返回一个类的子类对象
使用静态工厂方法返回一个类的子类对象,这无疑大大提高了代码的可扩展性,即使后面新建了一个子类也只需要加一个静态工厂方法即可。
public class MBank extends Bank{
}
创建Bank的子类MBank,并在Bank类中添加一个创建子类对象的静态工厂方法
public static Bank getMBank(){
bank = new MBank();
return bank;
}
这样即使后面又创建了新的子类,也只需要添加一个对应的静态工厂方法即可,因为它可以返回父类的任何子类对象。
总结
总之,使用静态工厂方法创建对象有很多好处,它相对于构造器,更利于阅读和代码的扩展,并且有很高的灵活性,但是相对的,这种创建对象的方式也有它的一些缺点。只是在日常业务代码开发过程中,很多人的第一反应就是使用构造器创建对象,其实我们更应该结合具体的场景选择更适合的方式。