注意:静态工厂方法不是设计模式中的工厂方法。

一个类向客户端提供静态工厂方法有如下好处:

  • 有名称,不用根据参数类型和顺序区分重载方法,让代码更易读
  • 是否每次调用都需要新对象是可控制的,对于不可修改的对象可以采取缓存对象来提高性能,例如可以使用==来判断对象是否相等,而不使用equals,可以提高性能。
  • 工厂方法体内可返回返回类型的任何子类型,这在选择返回对象的类型上有很大的灵活性。一个对外隐蔽了实现类(即所返回的对象的类型对外是不可见的)的API是非常紧凑的API。这种技巧本身把自己引导成了基于接口的框架(接口为静态工厂方法提供返回类型)。接口不能有静态方法,因此按惯例返回类型为接口Type的静态工厂方法会放在一个不可实例化的类Types中:例如Java集合框架中的Collections有32个对集合接口的非常方便的实现,分别提供不可修改集合、同步集合等等,几乎所有这些实现都是通过一个不可实例化的类(java.util.Collections)的静态工厂方法导出,这些工厂所返回的类都是非public的。当前集合框架API比导出32个public类要更小,不单只在API的代码量上得到减少,同时还在概念的重量级方面。用户一眼就知道所返回的对象正如接口所描述的一样,不需要读取额外的类实现文档。另外,使用这样一种静态工厂方法需要客户端使用接口来引用这个工厂方法所返回的对象,而不是使用实现类引用,这是一个好的实践。不只由静态工厂返回的对象的类型可以是非public的,根据传入静态工厂的参数的不同,这个返回对象的类也是可变的,只要是静态工厂方法声明的返回值类型的子类型就都是允许的。静态工厂返回值类型也是可以在各发布版间变化的,以增强可维护性和性能。Java1.5引入的java.util.EnumSet没有public构造器,只有静态工厂,这些静态工厂根据底层枚举类型的大小返回两个实现中的一个:如果元素小于等于64,静态工厂返回一个RegularEnumSet实例,它由单个long支持; 如果枚举类型有大于64个元素,静态工厂会返回一个JumboEnumSet实例,它由一个long数组支持。这两个实现类对客户端是不可见的。

由静态工厂方法返回的对象的类甚至不必在编写静态工厂方法所在的类时就存在。静态工厂的这种灵活性是服务提供者框架(service provider framework)的基石,例如JDBC。服务提供者框架是一个系统,在这个系统中,服务提供者实现服务,这个系统让这些实现对客户端可用,从而把客户端与实现分离。

服务提供者框架有三个基本的组件:由提供者实现的服务接口、系统用于注册服务实现并让其对客户端可用的提供者注册API、客户端用于获取服务实现的服务访问API。服务访问API通常允许让客户端指定某些条件以便选择一个提供者,但客户端不是必须要指定,如果没有指定,API会返回一个默认实现。服务访问API就是构成服务提供者框架的基石的灵活静态工厂。

服务提供者接口有一个可选的组件:服务提供者接口,由提供者用于创建他们自己的服务实现的实例。在没有服务提供者接口的情况下,实现是通过类名进行注册,并通过反射进行实例化。在JDBC中,Connection就是服务接口,DriverManager.registerDriver()就是服务提供者注册接口,DriverManager.getConnection()是服务访问接口,Driver是服务提供者接口。

现在有许多服务提供者框架模式的变种,例如,通过使用适配器,服务访问API可以返回比提供者所需要的服务接口更加丰富的服务接口,下面是一个服务提供者接口及其一个默认实现:

// Service provider framework sketch
// Service interface
public interface Service {
    ... // Service-specific methods go here
}
// Service provider interface
public interface Provider {
    Service newService();
}
// Noninstantiable class for service registration and access
public class Services {
    private Services() { }  // Prevents instantiation (Item 4)
    // Maps service names to services
    private static final Map<String, Provider> providers =
        new ConcurrentHashMap<String, Provider>();
    public static final String DEFAULT_PROVIDER_NAME = "<def>";
// Provider registration API
    public static void registerDefaultProvider(Provider p) {
        registerProvider(DEFAULT_PROVIDER_NAME, p);
    }
    public static void registerProvider(String name, Provider p){
        providers.put(name, p);
    }
// Service access 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(
                "No provider registered with name: " + name);
        return p.newService();
    }
}

  • 减少创建参数化类型实现时的冗余信息

没有使用静态工厂时:

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

遗憾的是,标准的集合类实现中,例如HashMap并没有类似上面定义的工厂方法。但可以把这种方法放到自己的工具类中,更加重要的是,可以在自己的参数化类中提供这种静态工厂方法。

只提供静态工厂方法的类的主要缺点在于不能被子类化,因为没有public或protected的构造器的类是不能被子类化的。

由public权限的静态工厂返回的非public类也是不能被子类化的,例如,不能子类化Collections里面的实现类,这可以说是因祸得福,因此这样可以促进程序员使用组合而不是继承。

另一个缺点在于静态工厂方法不易与其它静态方法区分开。

主要是因为静态工厂方法不像构造器那样明显地出现在API文档中,因此很难知道如何使用类中提供的静态工厂来代替构造方法实例化对象。可以通过在类或接口中写注释来说明,并且让静态工厂方法名遵循约定:

valueOf、of、getInstance、newInstance、getType、newType

总之,静态工厂和构造方法各有优缺点,但一向在使用构造器之前优先考虑使用静态工厂。

转载于:https://www.cnblogs.com/mark-chan/p/5401666.html

使用静态工厂方法而不是构造器相关推荐

  1. 第1条:考虑采用静态工厂方法代替构造器

    第1条:考虑采用静态工厂方法代替构造器 第1条:考虑采用静态工厂方法代替构造器 对类而言,为了让客户端获取它自身的一个实例,最常用的方法就是提供一个公有的构造器.还有一种应该被程序员重视的方法:类提供 ...

  2. 第一条:考虑用静态工厂方法代替构造器

    转载链接:https://www.jianshu.com/p/ceb5ec8f1174 1.序:什么是静态工厂方法 在 Java 中,获得一个类实例最简单的方法就是使用 new 关键字,通过构造函数来 ...

  3. 《Effective Java》学习笔记 - (1) 使用静态工厂方法代替构造器

    文章目录 前言 使用静态工厂方法代替构造器 1. 优点 1.1 静态工厂方法有名称 1.2 不必每次调用的时候都创建一个对象 1.3 可以返回类型的任何子类型的对象 1.4 所返回的对象的类型可以随着 ...

  4. 01、静态工厂方法替代构造器

    考虑用静态工厂方法替代构造器 考虑使用静态工厂方法来替代构造器的原因: 静态工厂方法有名称:普通的构造器中,参数并不能很好地描述返回对象的特点,代码的阅读性不好. 考虑下面的程序: Random ra ...

  5. 构造函数还是静态工厂方法?

    我相信Joshua Bloch在他的非常好的书" Effective Java"中首先说了它:与构造函数相比,静态工厂方法是实例化对象的首选方法. 我不同意. 不仅因为我相信静态方 ...

  6. 《Effective Java》读书笔记 Item 1:考虑静态工厂方法,而不是构造器

    众所周知,要想能获取一个类的实例,该类得要提供一个public的构造器.但是<Effective Java>书中说还有一个方法,那就是提供静态工厂方法(static factory met ...

  7. 静态工厂方法代替构造器实例_静态工厂方法与传统构造方法

    静态工厂方法代替构造器实例 之前,我已经讨论过一些关于Builder模式的信息 , Builder Pattern是一种有用的模式,用于实例化具有几个(可能是可选的)属性的类,这些属性可以使读取,编写 ...

  8. java 静态工厂方法代替构造器的好处

    Java 的静态工厂方法 序:什么是静态工厂方法 Effective Java 2.1 静态工厂方法与构造器不同的第一优势在于,它们有名字 2.2 第二个优势,不用每次被调用时都创建新对象 2.3 第 ...

  9. 第1条:考虑用静态工厂方法代替构造器

    为了获得一个类的实例,有两种办法1.类提供一个公有的构造器 2.类提供一个公有的静态工厂方法. 静态工厂方法的优势: 1.有名称. 慎重地选择方法名称能突出多个构造器的区别,例如使用BigIntege ...

最新文章

  1. 真实记录疑似Linux病毒导致服务器 带宽跑满的解决过程
  2. AI制药来了!新药研发或告别“十年磨一剑”
  3. Oracle\MS SQL Server的数据库多表关联更新UPDATE与多表更新
  4. Google开源OCR项目Tesseract训练(自己训练的记录,未成功)
  5. 矩阵相乘取共轭_正交矩阵学习小结
  6. 上海计算机职业学校排名2015年,2015年上海各区学校教育资源实力排行榜
  7. java集合详解_Map、Set、List及其子类和接口你都明白吗?看这篇Java集合超详解
  8. 领域驱动 开源项目_在开源领域建立职业的建议
  9. Jvm(20),如何定义为垃圾对象----引用计数法
  10. 刚刚用鸿蒙跑了个“hello world”!跑通后,我特么开始怀疑人生....
  11. verilog中signed的使用
  12. ubunbtu下基于c++实现MQTT客户端通信
  13. 在职读研犹如飞轮效应,社科院与杜兰大学金融管理硕士与你奔赴未来
  14. 【九度】题目1419:文献排序
  15. 大数据入门级学习攻略
  16. 王姨劝我学HarmonyOS鸿蒙2.0系列教程之三Ability概述调用方法!
  17. ESP32:使用TFT_eSPI库驱动TFT串口屏
  18. Qt 安装包官方下载地址
  19. 求 柱状体、三菱体、长方体的体积
  20. android手机投影至mac,一键投影MAC一款无线工具

热门文章

  1. qq传输文件的软件测试点,超强新功能 QQ传文件夹测试版抢先试用
  2. 为什么计算机打不开系统盘了,为什么我从装了系统之后进入‘我的电脑’发现F/E盘都打不开了。系统提示:ses.exe找不到!...
  3. 卷积神经网络的整体结构、卷积层、池化、python实现
  4. bat执行exe程序_dos命令start教程,并行运行exe程序或者启动bat批处理cmd脚本
  5. python嵩天课后题及答案第二章_课后参考答案-第二章部分习题参考答案
  6. java 传递bean_Java:如何将值从类/ bean传递给servlet
  7. npm install packagename 安装失败的解决办法
  8. sqoop导出数据单mysql_sqoop导出hive表数据到mysql
  9. 关联的两个字段度需要建立索引吗_索引那些事儿
  10. miracast投屏软件下载_手机画面如何投屏到电视?