如何使用 YAML 配置文件实例化具有对象参数的新对象? [英] How to instantiate new objects with object parameters using YAML config file?
问题描述
我正在尝试使用配置文件来允许用户选择实现某些抽象类或接口的具体聚类算法.每种算法的先决条件输入可能略有不同.一个概念上的小例子:
I am trying to use a config file to allow a user to choose a concrete clustering algorithm that implements some abstract class or interface. Each algorithm may have slightly different pre-requisite inputs. A small conceptual example:
KMedoids
只需要用户设置k
即可.SpectralClustering
还需要k
但还需要其他一些东西,例如表示图类型的Enum
s,以及要使用的拉普拉斯算子的类型在其内部计算中.
KMedoids
just needs to havek
set by the user.SpectralClustering
also needsk
but also needs several other things likeEnum
s representing the type of graph, and the type of laplacian to use in its internal calculations.
两者的共同点定义在一个抽象类中.
The things the two have in common are defined in an abstract class.
为了使事情更一般,我编了一个虚拟示例.假设我有一个 Configuration
类,它将被传递给一个引擎".或司机"根据生成的 Configuration
实例完成工作.
To make things more general, I made up a dummy example. Let's say I have a Configuration
class that will be passed to an "engine" or "driver" of sorts to complete a job based on the instance of Configuration
generated.
public class Configuration {
private AbstractAlgorithm algo;
private AbstractParameter param1;
private ConcreteEnum.Enum1 param2;
private ConcreteEnum.Enum2 param3;
// getters and setters...
然后我有课
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
对象,该对象可以被传递给使用它的东西?
My question then is: how would the accompanying .yaml
file look so that it could be parsed into an instantiated Configuration
object that could be passed on to something that uses it?
推荐答案
和序列化一样,你的类应该有一个没有参数的构造函数:
As usual with serialization, your classes should have a constructor with no arguments:
abstract class AbstractAlgorithm {
public AbstractParameter abstractParam;
}
public class ConcreteAlgorithm extends AbstractAlgorithm {
public ConcreteEnum.Enum1 param1;
public ConcreteEnum.Enum2 param2;
}
他们除了字段之外的任何接口都与这个问题无关.我公开了这些字段,因为当您进行反序列化时,除非您想在 setter 中处理给定的值,否则您将使用 setter.
Whatever interface they have besides the fields is irrelevant to this question. I made the fields public since there is not really a point for them not to be when you're doing deserialization unless you want to process the given values in setters, in which case you would use setters.
现在定义了这些类型后,加载将按如下方式工作:
Now with these types defined, loading will work as follows:
Constructor constructor = new Constructor();
constructor.addTypeDescription(
new TypeDescription(ConcreteAlgorithm.class, new Tag("!concrete")));
yaml = new Yaml(constructor);
AbstractAlgorithm = yaml.loadAs(someInput, AbstractAlgorithm.class);
并且正在加载的 YAML 看起来像这样:
and the YAML being loaded would look like this:
--- !concrete
abstractParam: spam
param1: egg
param2: sausage
---
是指令结束标记,它开始文档的内容并且是可选的.我们在这里使用它是为了明确以下标记适用于文档的根节点.
The ---
is the directives end marker, which starts the document's content and is optional. We use it here to make clear that the following tag applies to the root node of the document.
!concrete
是根节点的标记.由于我们使用 SnakeYAML 注册它,这将导致 SnakeYAML 从该文件构造一个 ConcreteAlgorithm 对象.
!concrete
is that tag for the root node. Since we register it with SnakeYAML, it will lead to SnakeYAML constructing a ConcreteAlgorithm object from this file.
以下键值对为 ConcreteAlgorithm 的每个字段提供值,包括继承的字段.SnakeYAML 将根据所用类的性质处理字段值 - AbstractParameter
如果它是一个类,可能希望在 YAML 文件中有一个嵌套映射.如果 AbstractParameter
是另一个抽象类并且具有 ConcreteParameter
作为实现,你会做
The following key-value pairs give values to each of the fields of a ConcreteAlgorithm, including the inherited field. SnakeYAML will process the field values depending on the nature of the used classes – AbstractParameter
may want to have a nested mapping in the YAML file if it's a class. If AbstractParameter
is another abstract class and has ConcreteParameter
as implementation, you would do
--- !concrete
abstractParam: !cp
droggel: jug
param1: egg
param2: sausage
并将 !cp
注册为 ConcreteParameter
的标记.然后,包含键 droggel
的嵌套映射将生成 ConcreteParameter
的实例并分配给字段 abstractParam
.
and register !cp
as tag for ConcreteParameter
. The nested mapping containing the key droggel
will then generate an instance of ConcreteParameter
and be assigned to the field abstractParam
.
由于您可以在任何级别提供标签,因此您可以在加载 YAML 的结构中的任何位置嵌套具有抽象类类型的字段.
Since you can give tags on any level, you can nest fields with abstract class type anywhere in the structure you load your YAML into.
这篇关于如何使用 YAML 配置文件实例化具有对象参数的新对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!