Effective Java学习(一):创建和销毁对象

Item1:考虑用“静态工厂”,而不是“构造器”

先来看个静态工厂的典型例子

// translate a boolean primitive value into a Boolean object reference
public static Boolean valueOf(boolean b) {
	return b ? Boolean.TRUE : Boolean.FALSE;
}

要注意的是,与设计模式中的“工厂模式”不同!

好处

  • 好处一:静态工厂有名字,而构造器没有

    • 可读性强,方法名即功能
    • 能区别入口参数差异(比如参数类型一样,只是顺序不一样,通过方法名字说明)
  • 好处二:可以避免创建新的对象

    • 比如上述例子,并未创建新对象
    • 对象控制(比如单例模式,在方法外创建好需要的对象,方法里调就完了)
  • 好处三:可以返回原返回类型的子类对象

    • 灵活性增强
    • API可以返回对象,同时可以使返回对象的类不是public的,更好的隐藏封装,API更简洁
    • 让人们专注于API,而非类文档
    • Java8已经支持接口里写公有的静态成员了,而Java9甚至支持私有静态方法
package food;
 
import food.Food;
 
/**
 * 服务-提供者框架模型,一种服务(打印食物信息)多个提供者,通过FoodFactory静态工厂方法自动获取提供者
 * 下文好处五中会提到这个模型
 */
public class FoodFactory {
 
    private FoodFactory(){
        super();
    }
    public static final String TYPE_APPLE = "Apple";
    public static final String TYPE_BANANA = "Banana";
    private static final String TYPE_DEFAULT = "Bread";
 
    public static Food getFoodByType(String foodType){
        Food food = null;
        try {
            // 通过反射机制拿到类,那也就无所谓它的访问权限了
            food = (Food) Class.forName("food."+foodType).newInstance();//传说中的反射机制
        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
            e.printStackTrace();
        }
        return food;
    }
 
    public static Food getDefaultFood(){
        return getFoodByType(TYPE_DEFAULT);
    }
}
  • 好处四:返回对象的类型随输入参数的不同而改变

    • 比如我money少于10元,那我就return一个包子类;否则,我return一个汉堡类
    • 当然你也可能传的是一个对象数组,我就去遍历这个数组。比如说我这个数组元素个数小于10,我就返回Regular类;否则,返回一个Special类。这都是用户看不到的细节
  • 好处五:当包含方法的类被写入时,返回对象的类不需要存在

    • 典型例子:JDBC(A service provider framework)

    • 一个好的服务提供者的框架,应该包含:

      • 服务接口 a service interface —— 实现服务
      • 提供者注册API a provider registration API —— 提供者用它来注册实现
      • 服务访问API a service access API —— 客户用它来获取服务对象【这个就是静态工厂的好处四】
// 注册/加载驱动 —— a provider registration API
Class.forName("com.mysql.cj.jdbc.Driver");
// 获取连接对象 —— a service access API
String url = "jdbc:mysql://localhost:3306/how2java?useUnicode=true&characterEncoding=UTF-8";
Connection connection = DriverManager.getConnection(url,"root","admin");
// 获取执行sql语句的表单对象 —— a service access API
String sql = "select * from account";
Statement statement = connection.createStatement();
// 执行sql —— a service interface 
ResultSet resultSet = statement.executeQuery(sql);
System.out.println("result = " + result);
// Driver is the provider interface

坏处

  • 坏处一:(仅提供静态工厂方法时)没有publicprotected的构造函数的类不能被继承

    • 其实也算是好处😄哈哈,为什么呢?因为这使我们多用策略模式中的组合,而非去继承​
  • 坏处二:程序员不好找到静态工厂方法,因为它在文档中并不显眼,需要我们自己注意

接下来就讲几个常见的静态工厂例子吧:

  • from—类型转换方法,它接收单个参数并返回此类型的相应实例,例如:Date d = Date.from(instant);
  • of—一个接收多个参数并返回包含它们的此类型实例的聚合方法,例如:Set faceCards = EnumSet.of(JACK, QUEEN, KING);
  • valueOf—比 from 和 of 更为详尽的替代方法,例如:BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
  • instance or getInstance—返回由其参数描述的实例(如果有),但不能说具体有相同的值,例如:StackWalker luke = StackWalker.getInstance(options);
  • create or newInstance—就像 instance 和 getInstance,但该方法保证每个调用都返回一个新的实例,例如:Object newArray = Array.newInstance(classObject, arrayLen);
  • getType—就像 getInstance,但在工厂方法位于不同类中使用。Type 是工厂方法返回的对象的类型,例如:FileStore fs = Files.getFileStore(path);
  • newType—就像 newInstance,但在工厂方法位于不用类中使用。Type 是工厂方法返回的对象的类型,例如:BufferedReader br = Files.newBufferedReader(path);
  • type—getType 和 newType 的简洁替代方法,例如:List litany = Collections.list(legacyLitany);

总结

总之呢,静态工厂和公有构造器各有优劣,但以后在创建对象时,我们一定要优先考虑“静态工厂”!

持续更新中…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值