公共静态工厂方法

时间:2010-11-02 15:51:59

标签: java factory-pattern public-method

首先请原谅我,如果这是一个非常愚蠢的问题,我只是想把这种语言学习到它的核心。我正在阅读Effective Java,第一章讨论静态工厂方法与构造函数。他们的利弊。很少有令我困惑的事情是:

  1. 静态工厂方法返回的对象的类是非公开的 - 究竟是什么意思?
  2. 与构造函数不同,每次调用时都不需要静态工厂方法来创建新对象 - 这是如何发生的?我只是为了获取一个新对象而调用工厂方法,我们是否在工厂方法中检查对象是否已经存在?
  3. 感谢。

5 个答案:

答案 0 :(得分:11)

  

静态工厂方法返回的对象的类是非公共的 -   究竟是什么意思?

这意味着静态工厂方法返回的对象的实际类可以是声明类型的子类,并且此子类不必是公共的。这只是客户端代码不应该关心的另一个实现细节。

  

与构造函数不同,静态工厂方法不需要创建新对象,每个>他们被调用的时间 - 这是怎么发生的?我只是为了获取一个新对象而调用工厂方法,我们是否在工厂方法中检查对象是否已经存在?

是的,这是可以做到的一种方式。但实际上,一切皆有可能。

答案 1 :(得分:5)

首先,感谢您选择Java-lit:Bloch的书是优秀的入门。

要回答你的第二个问题('不像构造函数静态工厂方法不需要在每次调用时创建一个新对象'),重要的是要意识到Bloch在这里说的是,在静态工厂中,你有选项:返回新对象或返回预先存在的对象。这一切都取决于你想做什么。

例如,假设您有一个非常简单的Money类型值类。您的静态工厂方法可能应该返回一个新实例 - 即具有Money特定值的新对象。所以,像这样:

public class Money { 

    private Money(String amount) { ... } /* Note the 'private'-constructor */

    public static Money newInstance(String amount) {
        return new Money(amount);
    }

}

但是,假设您有一些管理某些资源的对象,并且您希望通过某些ResourceManager类同步对该资源的访问。在这种情况下,您可能希望静态工厂方法将自身的相同实例返回给每个人 - 强制每个人都通过同一个实例,以便1个实例可以控制该过程。这遵循单例模式。像这样:

public ResourceManager {

    private final static ResourceManager me = new ResourceManager();

    private ResourceManager() { ... } /* Note the 'private'-constructor */

    public static ResourceManager getSingleton() {
        return ResourceManager.me;
    }
}

上述方法强制您的用户只能使用单个实例,从而可以精确控制谁(以及何时)可以访问您正在管理的任何内容。


要回答你的第一个问题,请考虑一下(诚然不是最好的例子,它非常特别):

public class Money {

    private Money(String amount) { ... }


    public static Money getLocalizedMoney( MoneyType localizedMoneyType, String amount ) { 
        switch( localizedMoneyType ) {
            case MoneyType.US:
                return new Money_US( amount );
            case MoneyType.BR:
                return new Money_BR( amount );
            default:
                return new Money_US( amount );
        }
    }
}

public class Money_US extends Money { ... }

public class Money_BR extends Money { ... }

请注意我现在可以这样做:

Money money = Money.getLocalizedMoney( user_selected_money_type );
saveLocalizedMoney( money );

同样,这是一个非常人为的例子,但希望它可以帮助你或多或少地看到布洛赫在这一点上所得到的。

其他答案都很好 - 我只是认为,作为初学者,有时看一些实际的代码会有所帮助。

答案 2 :(得分:2)

当您使用new关键字时,您作为开发人员知道JDK将创建该对象的新实例。作者所说的,当您使用静态方法时,开发人员不再知道该方法是创建新实例还是可能正在执行其他操作。还有其他的东西可以,重用缓存数据,对象池,创建私有实现并返回类的子类。

答案 3 :(得分:1)

  

静态工厂方法返回的对象的类是非公共

静态工厂方法通常会返回一个类型为接口的对象(最常见),或者有时会返回一些基类(不常见)。在任何一种情况下,您都不知道返回对象的确切类。

这样做的好处是获得一个你知道的行为的对象,而不必担心它实例化的类的混乱细节。

  

与构造函数不同,每次调用时都不需要静态工厂方法来创建新对象

要理解这一点,请考虑使用单例的情况。您可以在某些工厂类上调用.getInstance()来获取某个对象的单例实例。通常,这样做的目的是创建对象的实例(如果它尚不存在),或者如果已经存在,则为现有实例提供。在任何一种情况下,您都会获得该对象的副本。但是你不知道(也不会)知道是否必须创建这个单例,或者是否已经构建过这个单例。

这样做的好处是可以为您管理对象的生命周期及其创建时间。

答案 4 :(得分:0)

通过查看一些使用静态工厂方法的这些属性的代码,可以回答两个问题。我建议看看Guava的ImmutableList

请注意no-arg工厂方法of()总是返回相同的实例(每次都不创建新实例)。如果仔细观察,您还会注意到,如果该对象本身是copyOf(Iterable),它的ImmutableList工厂方法实际上会返回传递给它的对象。这两个都利用了ImmutableList保证永不改变的事实。

另请注意其中的各种工厂方法如何返回不同的子类,例如EmptyImmutableListSingletonImmutableListRegularImmutableList,而不会暴露这些对象的类型。方法签名只显示它们返回ImmutableListImmutableList的所有子类都具有包私有(默认)可见性,使它们对库用户不可见。这提供了多个实现类的所有优点,而不会从用户的角度添加任何复杂性,因为它们只允许将ImmutableList视为单一类型。

除了ImmutableList之外,Guava中的大多数可实例化类都使用静态工厂方法。 Guava还举例说明了Effective Java中提出的许多原则(这并不奇怪,因为它是由这些原则设计的,并且是在Josh Bloch本人的指导下完成的),因此您可能会发现将它更多地看作是有用的。重读这本书。