经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
Effective Java 第三版读书笔记——条款1.考虑使用静态工厂方法替代构造器
来源:cnblogs  作者:LeeFire  时间:2018/11/6 10:22:12  对本文有异议

获取一个类的实例的传统方法是使用公开的构造器,除此之外,一个类还可以提供公开的静态工厂方法(static factory method)来返回它的实例。例如 Boolean 类中的 valueOf 方法,这个方法将基本类型 boolean 转换为一个 Boolean 对象的引用:

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

:静态工厂方法与设计模式中的工厂方法不同。

静态工厂方法的优点:

  • 与构造器不同,静态工厂方法拥有自己的名字。考虑一个场景: BigInterger 类的一个构造器 BigInterger(int, int, Random) 可能返回一个素数,然而传统的构造器不能很直观地表达出来,我们可以用一个静态工厂方法 BigInteger.probablePrime 使表达变得更清晰。

    此外,如果一个类需要几个参数类型相同的构造器,它只能打乱参数的顺序来进行区别,这使得类的构造变得十分困难。此时可以考虑使用静态工厂方法,这些方法拥有相同的参数类型,但你可以赋予它们精心挑选的名字,使它们的区别变得明显。

  • 当静态工厂方法被调用时,它们不需要每一次都创建一个新的对象。如开篇的 Boolean.valueOf(boolean) 所示,这个方法从来不创建对象,它只是返回 Boolean 类中已经创建的对象:

    1. public static final Boolean TRUE = new Boolean(true);
    2. public static final Boolean FALSE = new Boolean(false);

    这有效地提升了程序的性能。这一技巧与设计模式中的享元模式(Flyweight)十分相似。

  • 静态工厂方法可以返回其返回类型的任何子类的对象。一个可能的应用场景:API 可以返回对象,而不需要将它们的类公之于众,以这种方式隐藏实现类将使这个 API 变得十分紧凑。这个技术适合于基于接口的框架(interface-based frameworks)。

  • 随着输入参数的不同,同一个静态工厂方法可以返回不同的子类。例如 EnumSet 类:

    1. public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
    2. Enum<?>[] universe = getUniverse(elementType);
    3. if (universe == null)
    4. throw new ClassCastException(elementType + " not an enum");
    5. if (universe.length <= 64)
    6. return new RegularEnumSet<>(elementType, universe);
    7. else
    8. return new JumboEnumSet<>(elementType, universe);
    9. }

    当底层枚举类型的元素不超过64个时,返回 RegularEnumSet,超过64个则返回 JumboEnumSet

  • 在编写包含静态方法的类时,返回对象的类不需要存在。这种灵活的静态工厂方法构成了服务提供者框架(service provider frameworks)的基础,比如Java的数据库连接 API(JDBC)。

静态工厂方法的缺点

  • 只提供静态工厂方法、不提供 publicprotected 构造器的类不能被继承(子类化)。这也可能因祸得福:它鼓励程序员使用组合而不是继承。
  • 静态工厂方法很难被程序员找到。在API文档中,静态工厂方法不能像构造器那样突出,这使得程序员难以找到它们来实例化一个类。

一些静态工厂方法的常用名称

  • from:一个类型转换方法,接受一个参数并返回这个类型的相应实例。

    1. Date d = Date.from(instant);
  • of:一个聚合方法,接受多个参数、将它们合并在一起并返回这个类型的相应实例。

    1. Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
  • valueOffromto 的更为详细的替代方式。

    1. BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
  • instancegetInstance:返回一个实例,该实例由其参数(如果有的话)描述,但不能说具有相同的值。

    1. StackWalker luke = StackWalker.getInstance(options);
  • createnewInstance:与 instancegetInstance 类似,除了该方法保证每个调用返回一个新的实例。

    1. Object newArray = Array.newInstance(classObject, arrayLen);
  • getType:与 getInstance 类似,当工厂方法在不同的类中时使用。Type 是工厂方法返回对象的类型。

    1. FileStore fs = Files.getFileStore(path);
  • newType:与 newInstance 类似,当工厂方法在不同的类中时使用。Type 是工厂方法返回对象的类型。

    1. BufferedReader br = Files.newBufferedReader(path);
  • typegetTypenewType 的简洁版。

    1. List<Complaint> litany = Collections.list(legacyLitany);
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号