如何使用 YAML 配置文件实例化带有对象参数的新对象?
How to instantiate new objects with object parameters using YAML config file?
我正在尝试使用配置文件来允许用户选择实现某些抽象 class 或接口的具体聚类算法。每种算法的先决条件输入可能略有不同。一个概念性的小例子:
KMedoids
只需由用户设置 k
。
SpectralClustering
还需要 k
但还需要其他一些东西,例如 Enum
s 表示图形的类型,以及在其内部计算中使用的拉普拉斯算子的类型。
两者的共同点在摘要中定义class。
为了使事情更通用,我编了一个虚拟示例。假设我有一个 Configuration
class 将被传递给各种“引擎”或“驱动程序”以根据生成的 Configuration
实例完成工作。
public class Configuration {
private AbstractAlgorithm algo;
private AbstractParameter param1;
private ConcreteEnum.Enum1 param2;
private ConcreteEnum.Enum2 param3;
// getters and setters...
然后我有 classes
abstract class AbstractAlgorithm{
AbstractParameter abstractParam;
public void setParam(AbstractParam p) {
this.abstractParam = p;
}
public RandomObject runAlgo(DataObject data);
}
和ConcreteAlgorithm
:
public class ConcreteAlgorithm extends AbstractAlgorithm {
ConcreteEnum.enum1 concreteParam1;
ConcreteEnum.enum2 concreteParam2;
public ConcreteAlgorithm(ConcreteParameter p1, ConcreteParameter p2) {
this.concreteParam1 = p1;
this.concreteParam2 = p2;
}
public abstract void runAlgo(DataObject data) {
if (abstractParam == null) {
throw new IllegalStateException();
} else {
// do calculations based on enums and abstractParam value
}
}
我的问题是: 随附的 .yaml
文件看起来如何,以便它可以被解析为实例化的 Configuration
对象,可以传递在使用它的东西上?
与序列化一样,您的 classes 应该有一个不带参数的构造函数:
abstract class AbstractAlgorithm {
public AbstractParameter abstractParam;
}
public class ConcreteAlgorithm extends AbstractAlgorithm {
public ConcreteEnum.Enum1 param1;
public ConcreteEnum.Enum2 param2;
}
除了字段之外,他们有什么界面与这个问题无关。我创建了这些字段 public ,因为当你进行反序列化时,它们没有意义,除非你想在 setter 中处理给定的值,在这种情况下你会使用 setter。
现在定义了这些类型,加载将按如下方式进行:
Constructor constructor = new Constructor();
constructor.addTypeDescription(
new TypeDescription(ConcreteAlgorithm.class, new Tag("!concrete")));
yaml = new Yaml(constructor);
AbstractAlgorithm = yaml.loadAs(someInput, AbstractAlgorithm.class);
加载的 YAML 将如下所示:
--- !concrete
abstractParam: spam
param1: egg
param2: sausage
---
是 指令结束标记 ,它开始文档的内容并且是可选的。我们在这里使用它来明确以下标记适用于文档的根节点。
!concrete
是根节点的标记。由于我们使用 SnakeYAML 注册它,它将导致 SnakeYAML 从该文件构造一个 ConcreteAlgorithm 对象。
以下键值对为 ConcreteAlgorithm 的每个字段赋值,包括继承的字段。 SnakeYAML 将根据使用的 classes 的性质处理字段值 – AbstractParameter
可能希望在 YAML 文件中有一个嵌套映射,如果它是 class。如果 AbstractParameter
是另一个抽象 class 并且有 ConcreteParameter
作为实现,你会做
--- !concrete
abstractParam: !cp
droggel: jug
param1: egg
param2: sausage
并将 !cp
注册为 ConcreteParameter
的标签。包含键 droggel
的嵌套映射将生成 ConcreteParameter
的实例并分配给字段 abstractParam
.
由于您可以在任何级别上提供标签,因此您可以在将 YAML 加载到的结构中的任何位置嵌套带有抽象 class 类型的字段。
我正在尝试使用配置文件来允许用户选择实现某些抽象 class 或接口的具体聚类算法。每种算法的先决条件输入可能略有不同。一个概念性的小例子:
KMedoids
只需由用户设置k
。SpectralClustering
还需要k
但还需要其他一些东西,例如Enum
s 表示图形的类型,以及在其内部计算中使用的拉普拉斯算子的类型。
两者的共同点在摘要中定义class。
为了使事情更通用,我编了一个虚拟示例。假设我有一个 Configuration
class 将被传递给各种“引擎”或“驱动程序”以根据生成的 Configuration
实例完成工作。
public class Configuration {
private AbstractAlgorithm algo;
private AbstractParameter param1;
private ConcreteEnum.Enum1 param2;
private ConcreteEnum.Enum2 param3;
// getters and setters...
然后我有 classes
abstract class AbstractAlgorithm{
AbstractParameter abstractParam;
public void setParam(AbstractParam p) {
this.abstractParam = p;
}
public RandomObject runAlgo(DataObject data);
}
和ConcreteAlgorithm
:
public class ConcreteAlgorithm extends AbstractAlgorithm {
ConcreteEnum.enum1 concreteParam1;
ConcreteEnum.enum2 concreteParam2;
public ConcreteAlgorithm(ConcreteParameter p1, ConcreteParameter p2) {
this.concreteParam1 = p1;
this.concreteParam2 = p2;
}
public abstract void runAlgo(DataObject data) {
if (abstractParam == null) {
throw new IllegalStateException();
} else {
// do calculations based on enums and abstractParam value
}
}
我的问题是: 随附的 .yaml
文件看起来如何,以便它可以被解析为实例化的 Configuration
对象,可以传递在使用它的东西上?
与序列化一样,您的 classes 应该有一个不带参数的构造函数:
abstract class AbstractAlgorithm {
public AbstractParameter abstractParam;
}
public class ConcreteAlgorithm extends AbstractAlgorithm {
public ConcreteEnum.Enum1 param1;
public ConcreteEnum.Enum2 param2;
}
除了字段之外,他们有什么界面与这个问题无关。我创建了这些字段 public ,因为当你进行反序列化时,它们没有意义,除非你想在 setter 中处理给定的值,在这种情况下你会使用 setter。
现在定义了这些类型,加载将按如下方式进行:
Constructor constructor = new Constructor();
constructor.addTypeDescription(
new TypeDescription(ConcreteAlgorithm.class, new Tag("!concrete")));
yaml = new Yaml(constructor);
AbstractAlgorithm = yaml.loadAs(someInput, AbstractAlgorithm.class);
加载的 YAML 将如下所示:
--- !concrete
abstractParam: spam
param1: egg
param2: sausage
---
是 指令结束标记 ,它开始文档的内容并且是可选的。我们在这里使用它来明确以下标记适用于文档的根节点。
!concrete
是根节点的标记。由于我们使用 SnakeYAML 注册它,它将导致 SnakeYAML 从该文件构造一个 ConcreteAlgorithm 对象。
以下键值对为 ConcreteAlgorithm 的每个字段赋值,包括继承的字段。 SnakeYAML 将根据使用的 classes 的性质处理字段值 – AbstractParameter
可能希望在 YAML 文件中有一个嵌套映射,如果它是 class。如果 AbstractParameter
是另一个抽象 class 并且有 ConcreteParameter
作为实现,你会做
--- !concrete
abstractParam: !cp
droggel: jug
param1: egg
param2: sausage
并将 !cp
注册为 ConcreteParameter
的标签。包含键 droggel
的嵌套映射将生成 ConcreteParameter
的实例并分配给字段 abstractParam
.
由于您可以在任何级别上提供标签,因此您可以在将 YAML 加载到的结构中的任何位置嵌套带有抽象 class 类型的字段。