Effective Java - 创建和销毁对象 - 静态工厂方法代替构造器

静态工厂方法代替构造器

读书笔记,仅供参考

ps: 静态工厂方法只是一个返回类的实例的静态方法, 与设计模式中的工厂方法并不一样

public static Boolean valueOf(boolean b) {
    return b? Boolean.TRUE: Bolean.FALSE;
}

工厂方法的优势

拥有名称

构造器的参数有时无法确切的描述返回的对象,静态工厂方法可以通过方法名进行表示, 所以当一个类需要多个相同签名(具有相同的方法名,相同个数和相同类型参数)的构造器时,可以使用静态工厂方法代替构造器

不必在每次都创建一个新对象

  1. 避免创建不必要的重复对象
  2. 不可变类可以使用预先构建好的实例或者是缓存的实例
  3. 有助于类控制实例是否存在,称为实例受控的类(instance-controlled)

    实例受控的类
  4. 可以被确保为 Singleton
  5. 可以被确保为不可实例化
  6. 使不可变的类可以确保不存在两个相等的实例,可以使用 == 代替 equals,提升性能

可以返回原返回类型的任何子类型

  • 适用于基于接口的框架(接口为静态工厂方法提供了自然返回类型,但是接口不能有静态方法,所有将方法放在一个不可实例化的类中)
    例子为 java.utils.Colllections 类,这个类是一个不可实例化的类,静态方法返回的类可以是非公有的。下面的代码是在这个类中找到的符合上面说法的例子。这里也证明了平常使用接口引用实现类的用法。
    public static <K, V> Map<K, V> checkedMap(Map<K, V> m,
                                              Class<K> keyType,
                                              Class<V> valueType) {
        return new CheckedMap<>(m, keyType, valueType);
    }
    private static class CheckedMap<K,V>
        implements Map<K,V>, Serializable {

    }
  • 服务提供者框架(Service Provider Framework)
    静态工厂返回的对象的类,在编写包含静态工厂方法的类时可以不存在,这构成了服务提供者框架的基础。如 JDBC。
    服务提供者框架:多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把它们从多个实现中解耦出来。
    三个重要组件:
    • 服务接口:提供者实现
    • 提供者注册API:系统注册实现类
    • 服务访问API:客户端获取服务实例
    • 服务提供者接口:提供者创建服务的实例(此组件可选)
//服务接口
public interface Service {

}
//服务提供者接口
public interface Provider {
    Service newService();
}
//服务注册和方位, 不可实例化的类
public class Services {
    private Service(){}
    private static final Map<String, Provider> provider = 
        new ConcurrentHashMap<String, Provider>();
    public static final String DEFAULT_PROVIDER_NAME = "<def>";
    //提供者注册API
    public static void registerDefaultProvider(Provider p) {
        registerProvider(DEFAULT_PROVIDER_NAME, p);
    } 
    public static void registerProvider(String name, Provider p) {
        providers.put();
    } 
    //服务访问API
    public static Service newInstance() {
        return newInstance(DEFAULT_PROVIDER_NAME);
    }
    public static Service newInstance(String name) {
        Provider p = providers.get(name);
        if(p == null)
            throw new IllegalArgumentException("***");
        return p.newService();
    }
}

这个服务者框架和我现在做的一个项目中一部分有相似的情况,项目是支付平台,支持支付宝和微信,所以有两个 service, AliPayService 和 WechatPayService,他们都实现了 InternalPayService 接口,在使用 spring 的情况下,使用如下代码

@Autowired
    private Map<String, InternalPayService> payServices;

可以自动得到一个Map,里面有两个KV,即上面两个实现类,可以说 spring 实现了上面的服务者框架。

在创建参数化类型实例时,使代码变得更加简洁

例子:

Map<String, List<String>> m = new HashMap<String, List<String>>();

假设实现了以下方法

public static <K, V> HashMap<K, V> newINstance() {
    return new HashMap<K, V>();
}

第一处的代码可修改为

Map<String, List<String>> m = HashMap.newInstance();

虽然现在的 jdk 已经可以不用再在后面重复类型参数了,精神可以学习。

缺点

类如果不含有公有的或者受保护的构造器,就不能被子类化

这一点可以鼓励使用复合,而不是继承

与其他静态方法没有区别

在查找时不方便

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值