Java成员初始化模式
我有一个班级,我的班级:Java成员初始化模式,java,oop,Java,Oop,我有一个班级,我的班级: public class MyClass { private MyComplexType member1; } 我必须在member1上进行一些非常密集的初始化。它很容易保证自己的方法,从MyClass构造函数调用 我的问题是,以下哪种格式最适合这种方法 private MyComplexType initMyComplexType() { MyComplexType result = new MyComplexType(); // extensiv
public class MyClass {
private MyComplexType member1;
}
我必须在member1
上进行一些非常密集的初始化。它很容易保证自己的方法,从MyClass
构造函数调用
我的问题是,以下哪种格式最适合这种方法
private MyComplexType initMyComplexType() {
MyComplexType result = new MyComplexType();
// extensive initialization on result...
return result;
}
这样称呼:
public MyClass() {
member1 = initMember1();
}
public MyClass() {
initMember1();
}
或
private void initMember1() {
member1 = new MyComplexType();
// extensive initialization on member1...
}
这样称呼:
public MyClass() {
member1 = initMember1();
}
public MyClass() {
initMember1();
}
对于私人会员来说,哪种风格更好?为什么?我会选择第一个选项,因为它更清楚地表达了init方法的目的,并明确地显示了数据流 更不用说它使init方法中的代码具有潜在的可重用性。如果以后需要初始化另一个变量,只需再次调用该方法即可,无需担心副作用。此外,如果另一个变量在另一个类中,您可以轻松地将该方法移动到两个地方都可以访问的地方
沿着这条线,我也会考虑将init方法保留到如<代码> doExsisivCeFinePosith以将它与实际的成员变量解耦。
选项1。除了Peter提到的原因之外,这是一个更好的实践,因为这样您就有了一个计算密集但无副作用的函数
,以及更轻但状态修改的构造函数。将这两个特性分开是公认的良好实践init()
此外,使用模板/工厂方法对扩展打开。在子类中重写它(或者使用模板方法重写它的一部分)更容易。同样,这要归功于计算与状态修改的分离
<>编辑:正如其他人所陈述的,也考虑重命名<代码> InCuffic MeCube()/<代码> <代码> Bug DistabeMeMeNe()/< > < P>只有第一个允许您将结果分配给最终成员,这对我来说已经足够了。第二种方法的另一个缺点是字段member1可能会将部分初始化的MyComplexType暴露给另一个线程 回复Jörn Horstmann的重写受保护静态方法示例:
public class StaticOverrideParent {
protected static void doSomething() {
System.out.println("Parent doing something");
}
}
public class StaticNoOverride extends StaticOverrideParent {
public static void main(String[] args) {
doSomething();
}
}
public class StaticOverride extends StaticOverrideParent {
protected static void doSomething() {
System.out.println("Doing something");
}
public static void main(String[] args) {
doSomething();
}
}
运行StaticNoOverride打印“家长正在做某事”。
运行StaticOverride打印“正在做某事” 已经给出了很好的理由(最终成员分配、多线程问题、提高可读性),技术上的理由非常好,对我来说已经足够了。我只想从Java教程中添加一点摘录: 通常,您会将代码放在 初始化实例中的实例变量 构造器。有两个 使用构造函数来 初始化实例变量: 初始化程序块和final方法 例如,初始值设定项阻塞 变量看起来就像静态的 初始值设定项阻塞,但没有 静态关键字:
{
// whatever code is needed for initialization goes here
}
Java编译器复制初始值设定项
块插入每个构造函数。
因此,可以使用这种方法
在用户之间共享一段代码
多个构造函数
无法在中重写最终方法
子类。本节将对此进行讨论
关于接口和继承的课程。
下面是一个使用期末考试的示例
用于初始化实例的方法
变量:
class Whatever {
private varType myVar = initializeInstanceVariable();
protected final varType initializeInstanceVariable() {
//initialization code goes here
}
}
这在以下情况下特别有用:
子类可能希望重用
初始化方法。方法是
final,因为调用非final
实例初始化期间的方法
可能会引起问题。约书亚·布洛克
在中对此进行了更详细的描述
我倾向于使用上述样式(除非我不希望在所有构造函数中都进行初始化,但这是不寻常的)。我更喜欢的是,而不是您描述的那种复杂的硬编码初始化。它可以更好地分离关注点,并为单元测试提供更好的环境。其他评论员给出了使用辅助函数初始化变量的充分理由。我只想补充一点,我实际上更喜欢使用私有或受保护的静态函数。这非常清楚地表明,这只是一个初始化助手,它不能以任何方式修改对象的其他状态,也不能被子类覆盖。同意,但是:我不会将其命名为
initMember1()
,因为它不仅初始化它,而且还创建对象。更好的名称是,根据具体情况,createMyComplexType()
或createMember1()
“使用模板/工厂方法可以扩展。在子类中重写它(或使用模板方法时重写它的一部分)更容易。”但是,(直接或间接)这样做不是一个好主意从构造函数调用虚拟方法。我甚至没有想到这一点。在这种特殊情况下,这不应该是一个问题,但仍然是:好的观点!这不是“覆盖”,就jvm而言,这是两个完全独立的函数。有关详细信息,请参见。也许您可以举个例子?我不认为复杂的初始化可以在Spring applicationContext中通过声明方式完成。对于复杂到不能直接放入声明式应用程序上下文的对象,可以提供FactoryBean使对象适应IoC容器。受保护的静态方法可以由子类重写,请参见我前面答案中的示例