Effective Java

来源:互联网 发布:modbus tcp编程实例 编辑:程序博客网 时间:2024/06/10 17:19

静态工厂方法代替构造器

读书笔记,仅供参考

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 已经可以不用再在后面重复类型参数了,精神可以学习。

缺点

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

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

与其他静态方法没有区别

在查找时不方便