如何使用 YAML 配置文件实例化具有对象参数的新对象? [英] How to instantiate new objects with object parameters using YAML config file?

查看:60
本文介绍了如何使用 YAML 配置文件实例化具有对象参数的新对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用配置文件来允许用户选择实现某些抽象类或接口的具体聚类算法.每种算法的先决条件输入可能略有不同.一个概念上的小例子:

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 但还需要其他一些东西,例如表示图类型的 Enums,以及要使用的拉普拉斯算子的类型在其内部计算中.
  • KMedoids just needs to have k set by the user.
  • SpectralClustering also needs k but also needs several other things like Enums 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆