拿一个有人想填写的骨架类来获取一系列网站上的RSS流:
public class RSSStream extends Thread {
public RSSStream(String rssStreamName,String rssURL,int refreshTime){
// constructor code goes here
}
}
现在,让我们考虑一下refreshTime必须高于零,并且rssURL应该是一个有效的http地址。
明显的反射是在构造函数中有一些值检查逻辑。但是,无论发生什么,对构造函数的调用都会实例化Object。这意味着如果值不允许它执行它的工作,则Object最终会变得无用。这也意味着最终应该转储或重用Object。
所以,这里有几个关于这个主题的问题:
欢迎您的所有答案。清楚地了解最常见的做法是很有趣的。
答案 0 :(得分:3)
一些最常见的事情:
如果使用FactoryMethod构造复杂对象,通常会有一个私有构造函数,并需要通过工厂进行实例化。这支持与工厂交换施工策略。
对于我来说,如果实例化不能发生,将在构造函数中抛出一个自定义(并且希望提供信息)异常:
公共类人员{
public Person(Integer id, String name) throws InvalidPersonException
if (name==null) throw new InvalidPersonException("You cant have a person without a name");
...
这可能会在实体持久性对象中造成混乱,主要是因为您希望这些对象没有逻辑,并且因为框架应该为您处理 - 例如如果你在hibernate中有一个包含(id,name)的bean并尝试持久化到一个名称必须为非null的表中,那么db抛出的错误或者你的配置应该就足够了。
答案 1 :(得分:2)
如果您需要执行的值检查可能会使对象实例处于损坏状态,那么您应该考虑创建工厂来生成实例。这将允许您在传递的参数无效时抛出异常。
但是,如果在验证失败的情况下,您的对象可以使用默认值在构造函数中“修复”,那么使用默认值为调用者提供一个无用但没有损坏的对象。
答案 2 :(得分:2)
如果构造函数抛出异常,则不会返回对象的引用,因此可以立即对对象进行垃圾回收。所以你不是在浪费记忆力。我认为这是在构建对象时进行验证的正确位置,尤其是不可变对象。
getInstance()是一个返回子类实例的工厂方法。当您根据具体情况返回不同的子类时,可以使用它。例如,Calendar.getInstance()在我的语言环境中返回GregorianCalendar,但如果我的语言环境设置不同,它可能会返回不同的实现。
有关创建对象的各种模式,请查看http://en.wikipedia.org/wiki/Creational_pattern
希望这有帮助
答案 3 :(得分:2)
getInstance()
和私有构造函数只是为了使用Singleton模式。但是,Java的Calendar
抽象类不是为Singleton使用此方法,而是使用默认时区和语言环境实例化默认实现(Gregorian)。可能这样做是因为Calendar
是抽象的,无法实例化。 GregorianCalendar
实际上有公共构造函数。@Required
annotation可以让容器抛出异常。答案 4 :(得分:2)
在这种特殊情况下,我只是在构造函数中进行参数验证,并抛出带有描述性错误消息的IllegalArgumentException。不会创建该对象,并且必须修复调用代码。
您也可以在getInstance()方法中执行此操作。使用getInstance()的一个原因是实例是非常可共享的,以减少您创建的对象的数量。例如,如果您可以拥有多个具有相同URL的RSSStream对象,则可以安装getInstance()来共享这些实例。 (这假设实例是不可变的。)
还有Builder模式。你有一个名为RSSStream.Builder的嵌套内部类,可以说:
RSSStream rss = new RSSStream.Builder.build(url)
.name("stack overflow")
.refreshTime(2)
.build();
此模式使您的客户端代码更具自我描述性,并确保您永远不会在无效状态下构建RSSStream(构建器的方法抛出IllegalArgumentException)。构建器足够灵活,可以替换所有公共构造函数。
我通常使用IllegalArgumentException,从构造函数中抛出它,或者使用验证方法(将错误检查代码从多个构造函数中分解出来)。我已经开始将Builder方法用于更重要的公共API,并且非常喜欢它。
您当然可以在域模型类中使用这些技术。
答案 5 :(得分:2)
如果验证失败,需要验证其参数的构造函数通常会抛出IllegalArgumentException
。当构造函数抛出异常时,不会担心“中途初始化”对象。