scala 在任何派生类的构造函数之后运行方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2906958/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Running a method after the constructor of any derived class
提问by Alexey Romanov
Let's say I have a Java class
假设我有一个 Java 类
abstract class Base {
abstract void init();
...
}
and I know every derived class will have to call init()after it's constructed. I could, of course, simply call it in the derived classes' constructors:
而且我知道每个派生类init()在构建后都必须调用。当然,我可以简单地在派生类的构造函数中调用它:
class Derived1 extends Base {
Derived1() {
...
init();
}
}
class Derived2 extends Base {
Derived2() {
...
init();
}
}
but this breaks "don't repeat yourself" principle rather badly (and there are going to be many subclasses of Base). Of course, the init()call can't go into the Base()constructor, since it would be executed too early.
但这严重违反了“不要重复自己”的原则(并且将有许多子类Base)。当然,init()调用不能进入Base()构造函数,因为它会过早地执行。
Any ideas how to bypass this problem? I would be quite happy to see a Scala solution, too.
任何想法如何绕过这个问题?我也很高兴看到 Scala 解决方案。
UPDATE: Here is a generic version of the Factory Method approach:
更新:这是工厂方法方法的通用版本:
interface Maker<T extends Base> {
T make();
}
class Base {
...
static <T extends Base> T makeAndInit(Maker<T> maker) {
T result = maker.make();
result.init();
return result;
}
}
UPDATE 2: This question is basically "how do you use Template Method for constructors"? And the answer seems to be, "You can, but it's a bad idea". So I can do a Template Factory (Template Method + Abstract Factory) instead.
更新2:这个问题基本上是“你如何为构造函数使用模板方法”?答案似乎是,“你可以,但这是个坏主意”。所以我可以做一个模板工厂(模板方法+抽象工厂)。
采纳答案by erickson
What happens in init()? It's likely that a better design could eliminate the method altogether, or at least relax the requirement that it execute after the sub-class' constructor. Be certain that init()does not make the object under construction visible to any other threads before the constructor completes, because that creates concurrency bugs.
会发生什么init()?更好的设计可能会完全消除该方法,或者至少放宽它在子类的构造函数之后执行的要求。可以肯定,init()不会使在建的对象可见的构造函数完成之前的任何其他线程,因为它创建并发错误。
As an (ugly) alternative, an abstract method could be implemented by sub-classes as a pseudo-constructor:
作为(丑陋的)替代方案,抽象方法可以由子类实现为伪构造函数:
abstract class Base {
Base() {
ctor();
init();
}
abstract void ctor();
abstract void init();
}
回答by Bozho
Avoid this. If you do it, any class that extends your DerivedXclass may decide to also call init()thus leaving the object in inconsistent state.
避免这种情况。如果你这样做,任何扩展你的DerivedX类的类都可能决定也调用,init()从而使对象处于不一致的状态。
One approach is to let the init()method be invoked manually by clients of your class. Have an initializedfield, and throw IllegalStateExcepionif any method that requires initialization is called without it.
一种方法是让init()您的类的客户端手动调用该方法。有一个initialized字段,IllegalStateExcepion如果没有它调用任何需要初始化的方法,则抛出。
A better approach would be to use a static factory method instead of constructors:
更好的方法是使用静态工厂方法而不是构造函数:
public Derived2 extends Base {
public static Derived2 create() {
Derived2 instance = new Dervied2();
instance.init();
return instance;
}
}
Update: As you suggest in your update, you can pass Builderto a static factory method, which will call the init()on the instance. If your subclasses are few, I think this is an overcomplication, though.
更新:正如您在更新中建议的那样,您可以将Builder传递给静态工厂方法,该方法将init()在实例上调用。不过,如果您的子类很少,我认为这是一种过度复杂化。
回答by Espen
In addition to Bozho's recommendation, an application container is excellent for the task.
除了 Bozho 的推荐之外,应用程序容器非常适合该任务。
Mark your init()method with the javax.annotation.PostConstructannotation and a rightly configured EJB or Spring container will execute the method after the dependency injections are finished, but before the object can be used by the application.
init()使用javax.annotation.PostConstruct注释标记您的方法,并且正确配置的 EJB 或 Spring 容器将在依赖项注入完成后、但在应用程序可以使用对象之前执行该方法。
An example method:
一个示例方法:
@PostConstruct
public void init() {
// logic..
}
In an enterprise application you can open resources to for example the files system in the init()method. This initialization can throw exceptions and should not be called from a constructor.
在企业应用程序中,您可以打开资源到例如方法中的文件系统init()。此初始化可能会引发异常,不应从构造函数调用。
回答by irreputable
if Java had it, we wouldn't see all these init() method calls in the wild.
如果 Java 有它,我们就不会在野外看到所有这些 init() 方法调用。
"surround child constructor with something" - that cannot be done in pure java. Too bad, because there can be very interesting applications, especially with anonymous class + instance initialization block.
“用一些东西包围子构造函数”——这在纯 Java 中是做不到的。太糟糕了,因为可以有非常有趣的应用程序,尤其是匿名类 + 实例初始化块。
factory and container - they can be helpful when native newdoesn't do the job; but that's trivial and boring, and won't work with anonymous classes.
工厂和容器 - 当本地人new不做这项工作时,它们会很有帮助;但这既琐碎又无聊,并且不适用于匿名类。
回答by Istao
Or use spring... you can do <beans default-init-method="init">, see Default initialization and destroy methods.
或者使用 spring... 你可以这样做<beans default-init-method="init">,请参阅默认初始化和销毁方法。
回答by Fred Haslam
If you are adverse to using factories for some reason, you could use the following trick:
如果您出于某种原因不喜欢使用工厂,则可以使用以下技巧:
trait RunInit {
def init():Unit
init()
}
class Derived1 extends Base with RunInit {
def init() = println("INIT'ing!")
}
This will run init() before the Derived1 constructor/body.
这将在 Derived1 构造函数/主体之前运行 init()。

