简体   繁体   English

何时使用构造函数,何时使用 getInstance() 方法(静态工厂方法)?

[英]When to use a Constructor and when to use getInstance() method (static factory methods)?

  1. When and how should we use a constructor我们应该何时以及如何使用构造函数

    Foo bar = new Foo();
  2. And when and how should we use getInstance() (static factory methods)我们应该何时以及如何使用 getInstance()(静态工厂方法)

     Foo bar = Foo.getInstance();

What is the difference between these two?这两者有什么区别? I have always used a constructor, but when should I use getInstance() instead?我一直使用构造函数,但是什么时候应该使用getInstance()呢?

Everybody seems to focus on singletons while I think that the question is actually about constructor vs static factory methods .每个人似乎都关注单例,而我认为问题实际上是关于构造函数与静态工厂方法

This is actually Item 1: Consider static factory methods instead of constructors of Effective Java by Joshua Bloch:这实际上是 Joshua Bloch 的第 1 条:考虑静态工厂方法而不是Effective Java的构造函数

Item 1: Consider static factory methods instead of constructors第 1 条:考虑静态工厂方法而不是构造函数

The normal way for a class to allow a client to obtain an instance of itself is to provide a public constructor.一个类允许客户端获取自身实例的正常方式是提供一个公共构造函数。 There is another technique that should be a part of every programmer's toolkit.还有另一种技术应该成为每个程序员工具包的一部分。 A class can provide a public static factory method , which is simply a static method that returns an instance of the class.一个类可以提供一个公共静态工厂方法,它只是一个返回类实例的静态方法。 Here's a simple example from Boolean (the boxed primitive class for the primitive type boolean ).这是Boolean的一个简单示例(原始类型boolean的装箱原始类)。 This method translates a boolean primitive value into a Boolean object reference:此方法将布尔原始值转换为Boolean对象引用:

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

Note that a static factory method is not the same as the Factory Method pattern from Design Patterns [Gamma95, p.请注意,静态工厂方法与设计模式中工厂方法模式不同[Gamma95,p。 107]. 107]。 The static factory method described in this item has no direct equivalent in Design Patterns .此项中描述的静态工厂方法在设计模式中没有直接等效项。

A class can provide its clients with static factory methods instead of, or in addition to, constructors.一个类可以为它的客户提供静态工厂方法来代替构造函数,或者除了构造函数之外。 Providing a static factory method instead of a public constructor has both advantages and disadvantages.提供静态工厂方法而不是公共构造函数既有优点也有缺点。

Advantages (quoting the book):优点(引用本书):

  • One advantage of static factory methods is that, unlike constructors, they have names.静态工厂方法的优点之一是,与构造函数不同,它们有名称。
  • A second advantage of static factory methods is that, unlike constructors, they are not required to create a new object each time they're invoked.静态工厂方法的第二个优点是,与构造函数不同,它们不需要在每次调用时都创建一个新对象。
  • A third advantage of static factory methods is that, unlike constructors, they can return an object of any subtype of their return type.静态工厂方法的第三个优点是,与构造函数不同,它们可以返回其返回类型的任何子类型的对象。
  • A fourth advantage of static factory methods is that they reduce the verbosity of creating parameterized type instances.静态工厂方法的第四个优点是它们减少了创建参数化类型实例的冗长。

Disadvantages (still quoting the book):缺点(还是引用书上的):

  • The main disadvantage of providing only static factory methods is that classes without public or protected constructors cannot be subclassed.只提供静态工厂方法的主要缺点是没有公共或受保护构造函数的类不能被子类化。
  • A second disadvantage of static factory methods is that they are not readily distinguishable from other static methods.静态工厂方法的第二个缺点是它们不容易与其他静态方法区分开来。

You've got two questions: when should I call a getInstance() method, and when should I create one?您有两个问题:什么时候应该调用getInstance()方法,什么时候应该创建一个?

If you're deciding whether to call a getInstance() method, it's easy.如果您决定是否调用getInstance()方法,这很容易。 You just need to read the class documentation to find out when you should call it.您只需要阅读类文档以了解何时应该调用它。 For example, NumberFormat provides a constructor and a getInstance() method;例如, NumberFormat提供了一个构造函数一个getInstance()方法; the getInstance() method will give you a localized NumberFormat . getInstance()方法会给你一个本地化的NumberFormat ForCalendar , on the other hand, the constructor is protected.另一方面,对于Calendar ,构造函数是受保护的。 You have to call getInstance() to get one.必须调用getInstance()来获得一个。

If you're deciding whether to create a getInstance() method, you need to decide what you're trying to accomplish.如果您正在决定是否创建getInstance()方法,您需要决定您要完成什么。 Either you don't want people to call your constructor (you're creating a singleton or a factory ), or you don't mind (as in NumberFormat above, where they're initializing some objects for the convenience of the caller).要么您希望人们调用您的构造函数(您正在创建单例工厂),要么您不介意(如上面的NumberFormat ,他们正在初始化一些对象以方便调用者)。


Long story short?长话短说? Don't worry about creating getInstance() methods in your own code.不要担心在您自己的代码中创建getInstance()方法。 If the time arises when they'll be useful, you'll know.如果到时候它们会派上用场,你就会知道。 And in general, if you can call a class's constructor, you're probably supposed to be doing that, even if the class provides a getInstance() method.一般而言,如果您可以调用类的构造函数,那么您可能应该这样做,即使该类提供了getInstance()方法。

The uses for getInstance methods: getInstance 方法的用途:

But most of the time your object will be a simple POJO and usage of public constructors is most practical and obvious solution.但大多数情况下,您的对象将是一个简单的POJO,并且使用公共构造函数是最实用和最明显的解决方案。

U1: getInstance From Another Class U1:从另一个类中获取实例

To return an instance of a different class:返回不同类的实例:

public class FooFactory {
    public static Foo getInstance() {
        return new Foo();
    }
}

NumberFormat.getInstance methods do this as they actually return instances of DecimalFormat . NumberFormat.getInstance方法会这样做,因为它们实际上返回DecimalFormat实例。

U2: Singleton Problems U2:单例问题

The singleton pattern restricts many of the benefits of object oriented programming.单例模式限制了面向对象编程的许多好处。 Singletons generally have private constructors, therefore you cannot extend them.单例通常具有私有构造函数,因此您不能扩展它们。 As you will be accessing it via its getInstance method and not referencing any interface, you will not be able to swap it out for another implementation.由于您将通过其 getInstance 方法访问它而不引用任何接口,因此您将无法将其替换为另一个实现。

If you can use both then it sound like a poorly implemented singleton pattern .如果您可以同时使用两者,那么这听起来像是一个实现不佳的单例模式

Use the second option if you intend to have only one single instance of the class in your system and make the constructor private then.如果您打算在您的系统中只有该类的一个实例,然后将构造函数设为私有,请使用第二个选项。

Use the first to allow building several objects of the class.使用第一个允许构建类的多个对象。

BUT do not give your class the both possibilities.但是不要给你的班级两种可能性。

Take care not to over-use singletons, only use them if really only one instance shall exist in the system otherwise you would limit the possibilities of re-use of your class in other projects.注意不要过度使用单例,只有在系统中真的只有一个实例时才使用它们,否则你会限制在其他项目中重用你的类的可能性。 It sounds interesting to be able to call getInstance from everywhere in your project but that makes unclear who actually owns that instance: nobody and/or all.能够从项目中的任何地方调用 getInstance 听起来很有趣,但这并不清楚谁真正拥有该实例:没有人和/或所有人。 If you have a lot of singletons in a project you can bet that the system is poorly designed (usually).如果你在一个项目中有很多单身人士,你可以打赌这个系统设计得很差(通常)。 Singletons should be used with care, the same advice than for global variables apply.应谨慎使用单例,与适用于全局变量的建议相同。

One case in which I always prefer a static factory over a regular constructor is when I know the object construction will be slowish.我总是喜欢静态工厂而不是常规构造函数的一种情况是,当我知道对象构造会很慢时。 I do simple initialization on constructor, but if I need to create something heavy I'll use a static method and document the behavior.我对构造函数进行了简单的初始化,但是如果我需要创建一些繁重的东西,我将使用静态方法并记录行为。

Singletons are evil.单身人士是邪恶的。 The problems I've seen surrounding it are not about re-use or extendability of a system (although I could see how that could occur), more so that I can't count the number of times i've seen obscure bugs in a system that arise from singletons.我看到的围绕它的问题与系统的重用或可扩展性无关(尽管我可以看到它是如何发生的),更多的是我无法计算我在一个系统中看到模糊错误的次数由单身人士产生的系统。

If you do need to use a singleton, ensure it's scope is extremely narrow, ie judiciously limit the number of other objects in your system that know about it.如果您确实需要使用单例,请确保它的范围非常狭窄,即明智地限制系统中了解它的其他对象的数量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM