繁体   English   中英

对工厂方法使用私有构造函数?

[英]Using private constructors for factory methods?

假设我要建立一个不变的Yahtzee计分卡类:

public final class Scorecard {

    private Map<Category, Integer> scorecard = new HashMap<Category, Integer>();

    public Scorecard() {
        // Instantiates a new empty scorecard
    }

    private Scorecard(Map<Category, Integer> scorecard) {
        this.scorecard = scorecard;
    }

    public Scorecard withScore(Category category, int[] roll) {
        newScorecard = new HashMap<Category, Integer>(scorecard); // Pretend that this is a deep-copy
        newScorecard.put(category, calculateScoreFromRoll(roll));
        return new Scorecard(newScorecard);
    }

    public int getScore(Category category) {
        return scorecard.get(category);
    }

}

基本上我不想公开类的内部。 如果我没有私有的构造函数,那么我将需要使用带有Map参数的公共构造函数,就像私有的一样(而且我也可能withScore()会丢失withScore()方法)以允许评分。 但这是执行工厂方法的有效方法吗?

一个非常常见的好模式是拥有所有私有构造函数和公共静态工厂方法:

public class MyClass {
    private MyClass() {}
    public static MyClass fromA(A foo) {
        MyClass o = new MyClass();
        o.field = bar; // etc
        return o;
    }
    public static MyClass fromB(B foo) {
        MyClass o = new MyClass();
        o.field = bar; // etc
        return o;
    }
}

注意:这允许具有相同参数类型的不同工厂方法,而构造函数不允许这样做。

工厂方法旨在允许您在不指定确切类型的情况下获取对象。

例如,来自有效Java,第二版:

在版本1.5中引入的类java.util.EnumSet(项目32)没有公共构造函数,只有静态工厂。 它们返回两个实现之一,具体取决于基础枚举类型的大小:如果它具有64个或更少的元素(如大多数枚举类型一样),则静态工厂将返回一个RegularEnumSet实例,该实例由一个long来支持; 如果枚举类型具有65个或更多元素,则工厂将返回JumboEnumSet实例,该实例由长数组支持。

客户端看不到这两个实现类的存在。 如果RegularEnumSet不再为小型枚举类型提供性能优势,则可以从以后的版本中删除它,而不会造成不良影响。 同样,如果事实证明对性能有利,将来的发行版可以添加EnumSet的第三个或第四个实现。 客户既不知道也不关心从工厂取回的物品的类别; 他们只关心它是EnumSet的某个子类。

使用构造函数代替您建议的静态方法会破坏工厂方法模式,因为直接使用构造函数就可以指定实现。

在您的情况下,如果要使用工厂方法,则可以将默认构造函数设为私有,以便客户端无法直接实例化ScoreCard 此时,您可以在工厂方法中自由使用ScoreCard任何特定实现。 例如,如果您创建了第二个ScoreCard类,该类由TreeMap支持,则可以通过更改静态工厂来切换客户端获得哪种ScoreCard实现。

暂无
暂无

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

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