2012-06-18 43 views
2

毫无疑问,这已被问及在这里回答了十几次,但我无法找到满意的答案。只允许父厂方法实例化子类

我有一个类的家庭,我只想通过像这样的静态方法(我可能在这里输入错别字,而不尝试编译)输入的抽象父类实例化。

public abstract class Papa { 
    public static Papa newInstance() { 
     String strClass = Papa.figureOutTheNameOfChildClassToInstantiate(); 
     Papa papa = (Papa) Class.forName(strClass).newInstance(); 
     return papa; 
    } 
    public abstract void doSomething(); 
    ... 
} 
public class Child extends Papa { 
    public void doSomething() { /* Do something */ } 
} 

这或多或少是我现在拥有的。我希望做的是确保Child只能通过工厂方法Papa.newInstance()实例化。我试图通过将Child的无参数构造函数设为私有,但Papa无法实例化它。

所以,我的问题是,我如何确保子实例只能通过工厂方法Papa.newInstance()创建?

回答

3

如果您绝对肯定地想要强制执行此操作,请给Papa一个受保护的构造函数,该构造函数采用Xyzzy类型的参数。使Xyzzy成为Papa中受保护的内部课程。给它一个私人的构造函数。现在,只有Papa可以创建Xyzzy的实例。由于您需要Xyzzy的实例来调用Papa的构造函数,并且由于Papa的子类必须从其构造函数调用其构造函数,所以您需要一个Xyzzy实例来调用Papa的任何子类的构造函数。因此,只有Papa可以调用其子类的构造函数。即使Xyzzy没有做任何事情。

子类可能会泄漏它们的Xyzzy实例,这将允许其他代码调用子类构造函数。但是你也可以通过使用单一使用来限制这一点,并且只能在单个静态工厂调用的上下文中使用。

但说实话,我不打扰!

+0

在内部类使用私有的构造是不是一个好主意 - 这迫使Java编译器生成存根构造带更多的知名度所以外部类可以实例化它们... – thkala

+0

实际上,如果不是因为直到现在我已经直接在我的项目中实例化Child(和它的兄弟姐妹),现在我不会打扰它想要识别并删除所有这些直接实例,并强迫自己始终使用未来的工厂方法。但即使如此,我仍然可以没有所有的大惊小怪... –

+0

对于这样的事情,类似Checkstyle的东西可能是谨慎的选择。有一天,我们将拥有一种语言,它具有足够强大的类型/访问系统来执行您想要做的事情,但在Java中这样做似乎可能会导致Lovecraftian。 –

3

几个可能的选择:

  1. 用于子类构造函数的默认可见性并把它们放在同一个包父类。这具有的缺点是这些类可以在同一个包中被其他类包括任何“兄弟”类来实例化。

  2. 让父类中的所有子类为nested classes。将它们标记为private static将使它们仅对父类可见。不幸的是,这也意味着有所有类的代码在同一个文件...