提问人:404 Name Not Found 提问时间:10/3/2023 更新时间:10/3/2023 访问量:62
Java DRY 无泄漏函数
Java DRY without leaking functions
问:
假设我有几个类是“弱单例”——不应该初始化多次的东西(注册侦听器等),但无论出于何种原因,我都不能使它们成为真正的单例甚至静态类,所以我能做的最好的事情就是警告自己(或者抛出一个我猜,但出于这个问题的目的,我如何处理它并不重要)。RuntimeException
public class WidgetManager {
private static boolean initialized = false;
// stuff to be initialized only once
public WidgetManager() {
if (initialized) Main.LOGGER.warn("Instantiating multiple instances of " + getClass().getName() + "!");
// initialize stuff
initialized = true;
}
}
有几个这样的“弱单例”,所以用手打字会很累。另外,我还觉得应该有更好的方法来做我的检查,以免重复我自己。
public class FooWidget {
private static boolean initialized = false;
// stuff
public FooWidget() {
if (initialized) // ...
// ...
}
}
public class BarWidget {
// this gets tiring
}
接口中的私有函数不起作用 - 使其中的函数仅在接口定义中可用。private
public interface WeakSingleton {
private void warnReinitialization(boolean initialized) {
if (initialized) Main.LOGGER.warn("...");
}
}
public class WidgetManager implements WeakSingleton {
private static boolean initialized = false;
public WidgetManager() {
warnReinitialization(initialized); // <-- Error, function not visible
initialized = true;
}
}
default
有效,但它到处暴露它。
public interface WeakSingleton {
default void warnReinitialization(boolean initialized) {
// ...
}
}
public class WidgetManager implements WeakSingleton {
private static boolean initialized = false;
public WidgetManager() {
warnReinitialization(initialized); // <-- Works here
initialized = true;
}
}
public class Main {
public static void main(String[] args) {
new WidgetManager().warnReinitialization(); // <-- Oops, the interface "leaked" ...
}
}
从表面上看,一个抽象类为我节省了定义布尔值并检查它的过程:
public abstract class WeakSingleton {
protected static boolean initialized = false;
protected void warnReinitialization() {
if (initialized) System.out.println("Warning: Reinitializing " + getClass().getName() + "!");
}
}
public class WidgetManager extends WeakSingleton {
private FooWidget foo;
private BarWidget bar;
public WidgetManager() {
warnReinitialization();
System.out.println("WidgetManager ctor");
initialized = true;
}
}
public class FooWidget extends WeakSingleton {
public FooWidget() {
warnReinitialization();
System.out.println("FooWidget ctor");
initialized = true;
}
}
public class BarWidget extends WeakSingleton {
public BarWidget() {
warnReinitialization();
System.out.println("BarWidget ctor");
foo = new FooWidget();
bar = new BarWidget();
initialized = true;
}
}
public class Main {
public static void main(String[] args) {
new WidgetManager();
}
}
不幸的是,它以其他方式中断:
user@host:~ $ javac *
user@host:~ $ java Main
WidgetManager ctor
FooWidget ctor
Warning: Reinitializing BarWidget!
BarWidget ctor
user@host:~ $
撇开有问题的设计不谈,有没有办法在不泄露检查功能的情况下实现我的目标,即减少检查所需的打字量?
感谢您抽出宝贵时间接受采访。
答:
-1赞
Cactusroot
10/3/2023
#1
您可以创建构造函数 ,类并创建一个实例:private
final
public final class WidgetManager {
public static final WidgetManager INSTANCE = new WidgetManager();
private WidgetManager() {
}
}
但我认为你不需要为侦听器设置单例,只需每次创建一个新实例,即使这些实例没有任何不同。
评论
0赞
Jorn
10/3/2023
如果你的单例需要自己的依赖项,这将不起作用
0赞
Cactusroot
10/3/2023
@Jorn 你是说循环引用吗?
0赞
Jorn
10/3/2023
不一定,任何依赖项都可以。因为当您初始化类(因此 .INSTANCE
0赞
Cactusroot
10/3/2023
@Jorn 如果要初始化的类具有依赖关系,但在编译时不知道这些依赖关系是什么,则可能不应使用单一实例模式。
0赞
Cactusroot
10/3/2023
@Jorn 如果 WidgetManager 在编译时知道它依赖于什么,例如 FooWidget 和 BarWidget,它可以简单地引用它们的 INSTANCE 字段,类加载器将首先加载它们,然后再加载 WidgetManager。我可能没有正确理解你。
评论
new X()
initialized = true
AtomicBoolean
initialized
initialized
true
volatile