Java 中的动态嵌套逻辑处理
Dynamic nested logic handling in Java
假设我有一个 xml 包含许多类似于此结构的嵌套逻辑运算符:
<?xml version="1.0" encoding="UTF-8"?>
<Or>
<And>
<Condition1>
<Condition2>
</And>
<Or>
<And>
<Condition3>
<Condition4>
<Or>
<Condition5>
<Condition6>
</Or>
</And>
<Condition7>
</Or>
<Condition8>
</Or>
结构的长度或深度没有限制。
我想在Java中表示这个结构,并且能够在任何给定时间确定根节点的布尔值。我能想到的唯一方法是某种嵌套列表排列,我试图避免这种情况,因为我担心这可能非常 "messy"。有没有更优雅的解决方案?
我在我的一个项目中遇到了类似的问题。我的解决方案是创建一个类型 Tree,其中包含一个名为 value
的字段和一个名为 descendants
.
的 Tree 列表
当节点是运算符时,值将填充运算符名称(AND、OR、NOT),子条件将添加到后代列表中。当它是条件时,值将包含条件并且列表将为空。
class 树还包含一个方法 evaluate(boolean neutralElement),returns 一个布尔值。在评估节点时,如果它不是运算符,我会简单地评估它。如果它是一个运算符,我会将当前运算符应用于它的后代(neutralElement 是必要的,因为由于项目条件,后代可能是一个空文本,如果它的 parent 是 OR 或正确,如果它的 parent 是一个 AND)。
这是一个有趣的问题。在我看来,使用 JAXB 很容易解决。这是一个小原型:
import java.io.StringReader;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import org.xml.sax.InputSource;
public class Test {
public static void main(String... args) {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" +
"<Or>\r\n" +
" <And>\r\n" +
" <Condition value = 'true'/>\r\n" +
" <Condition value = 'true'/>\r\n" +
" </And>\r\n" +
" <And>\r\n" +
" <Condition value = 'false'/>\r\n" +
" <Condition value = 'true'/>\r\n" +
" <Or>\r\n" +
" <Condition value = 'false'/>\r\n" +
" <Condition value = 'true'/>\r\n" +
" </Or>\r\n" +
" </And>\r\n" +
" <Condition value = 'false'/>\r\n" +
" <Condition value = 'false'/>\r\n" +
"</Or>";
try {
Evaluable o = (Evaluable) JAXBContext.newInstance(BooleanOperators.class, Condition.class).createUnmarshaller()
.unmarshal(new InputSource(new StringReader(xml)));
System.out.println(o);
System.out.println(o.evaluate());
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
interface Evaluable {
static final Evaluable TRUE = of(true);
static final Evaluable FALSE = of(false);
boolean evaluate();
static Evaluable of(boolean result) {
return new Evaluable() {
@Override
public boolean evaluate() {
return result;
}
};
}
}
@XmlAccessorType(XmlAccessType.NONE)
@XmlSeeAlso({ And.class, Or.class })
abstract class BooleanOperators implements Evaluable {
@XmlAnyElement(lax = true)
protected List<Evaluable> evaluables;
@Override
public String toString() {
return getClass().getSimpleName() + " {" + evaluables + "}";
}
}
@XmlRootElement(name = "And")
@XmlAccessorType(XmlAccessType.NONE)
class And extends BooleanOperators {
@Override
public boolean evaluate() {
if (evaluables == null || evaluables.isEmpty()) {
return true;
}
return evaluables.stream().reduce(TRUE, (i, j) -> Evaluable.of(i.evaluate() && j.evaluate())).evaluate();
}
}
@XmlRootElement(name = "Or")
@XmlAccessorType(XmlAccessType.NONE)
class Or extends BooleanOperators {
@Override
public boolean evaluate() {
if (evaluables == null || evaluables.isEmpty()) {
return true;
}
return evaluables.stream().reduce(FALSE, (i, j) -> Evaluable.of(i.evaluate() || j.evaluate())).evaluate();
}
}
@XmlRootElement(name = "Condition")
@XmlAccessorType(XmlAccessType.NONE)
class Condition implements Evaluable {
@XmlAttribute(required = true, name = "value")
private boolean result;
@Override
public boolean evaluate() {
return result;
}
@Override
public String toString() {
return "Condition (" + result + ")";
}
}
假设我有一个 xml 包含许多类似于此结构的嵌套逻辑运算符:
<?xml version="1.0" encoding="UTF-8"?>
<Or>
<And>
<Condition1>
<Condition2>
</And>
<Or>
<And>
<Condition3>
<Condition4>
<Or>
<Condition5>
<Condition6>
</Or>
</And>
<Condition7>
</Or>
<Condition8>
</Or>
结构的长度或深度没有限制。
我想在Java中表示这个结构,并且能够在任何给定时间确定根节点的布尔值。我能想到的唯一方法是某种嵌套列表排列,我试图避免这种情况,因为我担心这可能非常 "messy"。有没有更优雅的解决方案?
我在我的一个项目中遇到了类似的问题。我的解决方案是创建一个类型 Tree,其中包含一个名为 value
的字段和一个名为 descendants
.
当节点是运算符时,值将填充运算符名称(AND、OR、NOT),子条件将添加到后代列表中。当它是条件时,值将包含条件并且列表将为空。
class 树还包含一个方法 evaluate(boolean neutralElement),returns 一个布尔值。在评估节点时,如果它不是运算符,我会简单地评估它。如果它是一个运算符,我会将当前运算符应用于它的后代(neutralElement 是必要的,因为由于项目条件,后代可能是一个空文本,如果它的 parent 是 OR 或正确,如果它的 parent 是一个 AND)。
这是一个有趣的问题。在我看来,使用 JAXB 很容易解决。这是一个小原型:
import java.io.StringReader;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import org.xml.sax.InputSource;
public class Test {
public static void main(String... args) {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" +
"<Or>\r\n" +
" <And>\r\n" +
" <Condition value = 'true'/>\r\n" +
" <Condition value = 'true'/>\r\n" +
" </And>\r\n" +
" <And>\r\n" +
" <Condition value = 'false'/>\r\n" +
" <Condition value = 'true'/>\r\n" +
" <Or>\r\n" +
" <Condition value = 'false'/>\r\n" +
" <Condition value = 'true'/>\r\n" +
" </Or>\r\n" +
" </And>\r\n" +
" <Condition value = 'false'/>\r\n" +
" <Condition value = 'false'/>\r\n" +
"</Or>";
try {
Evaluable o = (Evaluable) JAXBContext.newInstance(BooleanOperators.class, Condition.class).createUnmarshaller()
.unmarshal(new InputSource(new StringReader(xml)));
System.out.println(o);
System.out.println(o.evaluate());
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
interface Evaluable {
static final Evaluable TRUE = of(true);
static final Evaluable FALSE = of(false);
boolean evaluate();
static Evaluable of(boolean result) {
return new Evaluable() {
@Override
public boolean evaluate() {
return result;
}
};
}
}
@XmlAccessorType(XmlAccessType.NONE)
@XmlSeeAlso({ And.class, Or.class })
abstract class BooleanOperators implements Evaluable {
@XmlAnyElement(lax = true)
protected List<Evaluable> evaluables;
@Override
public String toString() {
return getClass().getSimpleName() + " {" + evaluables + "}";
}
}
@XmlRootElement(name = "And")
@XmlAccessorType(XmlAccessType.NONE)
class And extends BooleanOperators {
@Override
public boolean evaluate() {
if (evaluables == null || evaluables.isEmpty()) {
return true;
}
return evaluables.stream().reduce(TRUE, (i, j) -> Evaluable.of(i.evaluate() && j.evaluate())).evaluate();
}
}
@XmlRootElement(name = "Or")
@XmlAccessorType(XmlAccessType.NONE)
class Or extends BooleanOperators {
@Override
public boolean evaluate() {
if (evaluables == null || evaluables.isEmpty()) {
return true;
}
return evaluables.stream().reduce(FALSE, (i, j) -> Evaluable.of(i.evaluate() || j.evaluate())).evaluate();
}
}
@XmlRootElement(name = "Condition")
@XmlAccessorType(XmlAccessType.NONE)
class Condition implements Evaluable {
@XmlAttribute(required = true, name = "value")
private boolean result;
@Override
public boolean evaluate() {
return result;
}
@Override
public String toString() {
return "Condition (" + result + ")";
}
}