【问题标题】:Final class with private constructor, what is the design principle带有私有构造函数的final类,设计原理是什么
【发布时间】:2016-12-28 23:13:59
【问题描述】:

我最近正在查看Netflix open source project 之一

在那里我发现使用了 final 类和私有构造函数。我完全知道

  1. final 是为了避免继承
  2. private 是禁止实例化

但我只是想知道为什么它们会一起使用。虽然方法是静态的,所以我们可以在不实例化的情况下使用它们,但仍然渴望了解其背后的设计原理。

【问题讨论】:

  • Netflix 出于某种原因不希望任何人扩展的单例类怎么样?
  • “private 是不允许实例化” 这是不正确的。类本身可以使用构造函数,例如在工厂方法中。
  • 它很可能是一个带有实用方法的类(都是static),这样的类不应该被扩展或实例化。这是一种常见的模式,虽然它不是非常面向对象的。
  • 如果类现在不使用它,则将类设为 final 并且构造函数私有实际上不允许实例化
  • 在 Java 1.5 之前,这是创建类型安全枚举类的常用方法,例如 TextAttribute、FileChannel.MapMode 和 HTML.Attribute。

标签: java private-constructor final-class


【解决方案1】:

使用此代码,您将拥有此功能

  • 不允许任何人子类 (extends) 您的类
  • 不允许实例化你的类
  • 将变量或类设置为 final 会提高性能(不多,但确实如此,并且在大型项目中用作常见做法会有所作为)

在这种情况下,我看不到单例模式来获取实例,因此,恕我直言,您正在寻找 Netflix API 中的帮助程序/实用程序类,其中开发团队使用一些标准做法来确保用户 以正确的方式使用他们的类:

StaticFinalClassExample.methodYouWantToCall();

另外,查看您链接的课程:

/**
 * This class consists exclusively of static methods that help verify the compliance of OP1A-conformant....
 */

还有:

//to prevent instantiation
private IMFConstraints()
{}

添加:

如果您想了解更多信息,请查看来自Joshua Bloch's Effective Java (2nd Edition) 的Item 4:

第 4 项:使用私有构造函数强制实现不可实例化

有时您会想要编写一个仅包含一组静态方法和静态字段的类。这样的类名声不好,因为有些人滥用它们来避免从对象的角度思考,但它们确实有有效的用途。

  • 它们可用于以java.lang.Math 或java.util.Arrays 的方式对原始值或数组的相关方法进行分组。
  • 它们还可以用于以java.util.Collections 的方式为实现特定接口的对象分组静态方法,包括工厂方法(第1 项)。
  • 最后,它们可用于对 final 类上的方法进行分组,而不是扩展类。

此类实用程序类并非旨在实例化:实例将是荒谬的。然而,在没有显式构造函数的情况下,编译器提供了一个公共的、无参数的默认构造函数。对于用户而言,此构造函数与其他构造函数没有区别。在已发布的 API 中无意中看到可实例化的类并不少见。

试图通过抽象类来强制执行不可实例化 不行。该类可以被子类化并且子类可以被实例化。此外,它会误导用户认为该类是为继承而设计的(第 17 条)。

但是,有一个简单的习惯用法可以确保不可实例化。仅当类不包含显式构造函数时才会生成默认构造函数,因此可以通过包含私有构造函数使类不可实例化。

【讨论】:

  • 我想知道这是行业或 Netflix 人员为了方便而创建的某种模式。如果将来我要使用这种模式,场景或测试用例会是什么?
  • @Sudip7 请查看我的更新以获取更多信息,这实际上不是 named 模式,而是 Joshua Bloch 在他的 Effective Java 书中的建议。什么(IMO)不仅仅是遵循它的好点。
  • 嗯,现在听起来更有说服力了。感谢这本好书的摘录。我想知道有没有这样的书可用于最新的 java 语言。
  • @Sudip7 我确信有效的 java 很快就会有第三版,(请 Joshua,工作!!!:))。
【解决方案2】:

该类由static 所谓的“实用程序”方法组成,因此您不需要它的实例,而且尝试获取它的实例是错误的。该类是最终类,因此客户端开发人员没有选择加入并扩展该类,因为这与原始类的意图背道而驰。

私有构造函数基本上有两种用途:在您想要限制创建的类的情况下严格控制实例化(例如,如果它需要大量资源)。在第一种情况下,您必须提供为客户端创建对象的static 工厂方法。 即:

public static IMFConstraints getInstance()

另一种情况是创建实例从不有效。在这种情况下,您提供static 方法,这些方法在类本身上调用。即:

public static void checkIMFCompliance(List<PartitionPack> partitionPacks)

你可以这样调用上面的方法:

// your cool client code here...
IMFConstraints.checkIMFCompliance(myPartitionPacks);
// more of your awesome code...

你链接的类是后一种情况。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-16
    • 1970-01-01
    相关资源
    最近更新 更多