gpt4 book ai didi

java - 带有抽象说明的工厂模式

转载 作者:行者123 更新时间:2023-11-29 09:00:58 25 4
gpt4 key购买 nike

我正在尝试按照此处描述的(带有示例)对工厂模式进行澄清: http://www.oodesign.com/factory-pattern.html

当我尝试实现“没有反射的类注册”示例时,我得到一个空指针异常。这与此处描述的相同:

factory method pattern with class registration produces a nullpointer exception

我明白为什么我会收到空​​指针异常(HashMap 在使用时未填充)并且我知道我可以通过在 class.forName 中使用来修复它strong>ma​​in 或在 Factory 实现中的静态 block 中。

但这不会破坏使用这种模式的目的吗?我认为这个想法是被创建的对象进行了注册 - 如果您被迫手动加载类以强制运行静态 block ,这是否违反了打开关闭原则?

示例代码如下:

主.java

public class Main {
public static void main(String[] args) {
Widget widgetA = WidgetFactory.getInstance().createWidget("WidgetA");
Widget widgetB = WidgetFactory.getInstance().createWidget("WidgetB");

widgetA.doSomething();
widgetB.doSomething();
}
}

小部件.java

public abstract class Widget {
protected abstract Widget createWidget();
public abstract void doSomething();
}

WidgetFactory.java

public class WidgetFactory {

private static WidgetFactory instance;

public static synchronized WidgetFactory getInstance() {
if (instance == null) {
instance = new WidgetFactory();
}
return instance;
}
private HashMap<String, Widget> widgets = new HashMap<>();

public void registerWidget(String id, Widget widget) {
widgets.put(id, widget);
}

public Widget createWidget(String id) {
Widget widget = widgets.get(id).create();
return widget;
}
}

WidgetA.java

public class WidgetA extends Widget {

static {
WidgetFactory.getInstance().registerWidget("WidgetA", new WidgetA());
}

@Override
protected Widget createWidget() {
return new WidgetA();
}

@Override
public void doSomething() {
System.out.println("WidgetA");
}

}

WidgetB.java

public class WidgetB extends Widget {

static {
WidgetFactory.getInstance().registerWidget("WidgetB", new WidgetB());
}

@Override
protected Widget createWidget() {
return new WidgetB();
}

@Override
public void doSomething() {
System.out.println("WidgetB");
}

}

如前所述,为了让它工作,我可以将它放在 Main 或 WidgetFactory 类中:

static {
try {
Class.forName(WidgetA.class.getName());
Class.forName(WidgetB.class.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace(System.err);
}
}

再一次,有人可以阐明应该如何实现此模式或分享一种技术来使此模式工作而无需在每次添加新的 Widget 子类时更新 Main 或 WidgetFactory 类吗?

感谢您的帮助!

最佳答案

你不能在没有反射的情况下执行此操作,因为 JVM 规范强制执行延迟类加载以节省资源。既没有用于 JVM 的参数,也没有“EagerClassLoader”(加载所有 jar 的所有类)文件)。另请参阅 this question 的答案和 this onethis one .

但是您可以使用以下代码通过反射加载 ONE 包的所有类:

public static void loadAllClassesOfPackage(String packageName) throws IOException, ClassNotFoundException {
ClassLoader classLoader = Thread.currentThread()
.getContextClassLoader();
assert classLoader != null;
String path = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
File packageDir = new File(resources.nextElement().getFile());
for (File file : packageDir.listFiles()) {
if (file.isFile() && file.getName().endsWith(".class")) {
Class.forName(packageName
+ '.'
+ file.getName().substring(0,
file.getName().length() - 6));
}
}
}

只要您只加载具有“合理”数量类的一个包的类,这不会占用太多资源。

我的示例代码的灵感来自 this sample code它还会加载子包的类。

编辑:

我用一个目录分支扩展了我的实现,以便它可以递归地工作。

public static void loadAllClassesOfPackageRecursively(String packageName)
throws IOException, ClassNotFoundException {
ClassLoader classLoader = Thread.currentThread()
.getContextClassLoader();
assert classLoader != null;
String path = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
File packageDir = new File(resources.nextElement().getFile());
for (File file : packageDir.listFiles()) {
if (file.isFile() && file.getName().endsWith(".class")) {
Class.forName(packageName
+ '.'
+ file.getName().substring(0,
file.getName().length() - 6));
} else if (file.isDirectory()) {
loadAllClassesOfPackageRecursively(packageName + '.' + file.getName());
}
}
}

关于java - 带有抽象说明的工厂模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17479477/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com