我正在为Java中的外部程序创建一个新的脚本生成器。这种语言支持变量,但它是一种无类型语言。这是我最初编写的代码示例:
public class Var
{
private String name;
private String type;
private float defaultValue;
private float lowerBound;
private float upperBound;
private float value;
private LinkedList<Float> valuesConstraint;
private String description;
private Category category;
private LinkedList<CvarDependency> dependencies;
...
}
通常var类型是Float,但它也可以是bool [0 | 1],String或int。 所以我最终做了这个实现:
abstract class Var
{
private String name;
...
}
public class IntVar extends Var
{
private int value;
private int defaultValue;
private int lowerBound; //-infinite
private int upperbound; //+infinite
...
}
public class FloatVar extends Var
{
private float value;
private float defaultValue;
private float lowerBound; //-infinite
private float upperbound; //+infinite
...
}
public class StringVar extends Var
{
private String value;
private String defaultValue; //empty string
...
}
public class BoolVar extends Var
{
private boolean value;
private boolean defaultValue;
private boolean lowerBound; //false <-> 0
private boolean upperbound; //true <-> 1
...
}
现在我必须将这些变量存储到LinkedList中,但是当我必须阅读其内容时,如何管理正确的强制转换?我已经读过使用这种方法不是一个好习惯:
Var var = Manager.getVar("namevar");
if( var.getClass().getName().equals("StringVar") )
...
else if( var.getClass().getName().equals("IntVar") )
...
else if( var.getClass().getName().equals("FloatVar") )
...
else if( var.getClass().getName().equals("BoolVar") )
...
有什么提示可以更好地解决这个问题吗?
答案 0 :(得分:0)
不要比较班级名称,比较班级:
if( var.getClass().equals(IntVar.class) ) {
IntVar intVar = (IntVar) var;
...
您也可以使用var instanceof IntVar
,但如果您编写一个扩展IntVar
的类,则可能会出现问题。
答案 1 :(得分:0)
您可以使用通用类型,但我不知道您需要对成员做什么......
public class Var<T extends Comparable<T>>
{
private String name;
private String type;
private T defaultValue;
private T lowerBound;
private T upperBound;
private T value;
private LinkedList<T> valuesConstraint;
private String description;
private Category category;
private LinkedList<CvarDependency> dependencies;
...
}
答案 2 :(得分:0)
不是让你的解释器直接提取和操作值,也许最好采用不同的方法并将操作定义为这样的方法:
abstract class Var
{
...
public Var add(Var var); // corresponds to var + otherVar; in script
public Var subtract(Var var); // corresponds to var - otherVar; in script
public Var unarySubtract(); // corresponds to -var; in script
...
}
这样你就可以通过调用这些方法来评估脚本中的表达式,并且你的类可以像这样重写和重载,例如:
public class IntVar extends Var
{
...
public IntVar add(IntVar var)
{
return new IntVar(value + var.value); // add another int
}
public FloatVar add(FloatVar var)
{
return new FloatVar(value + var.value); // add another float (and cast result to float? up to you whether you want to do this...)
}
public StringVar add(StringVar var)
{
return new StringVar("" + value + var.value); // add a string, and cast to string (for string concatenation)
}
public Var add(Var var)
{
throw new OperationNotSupportedException(); // no other types can be added to an IntValue so throw an exception
}
public Var subtract(Var var) {...}
public IntVar unarySubtract()
{
return new IntVar(-value);
}
...
}
通过这种方式,您可以根据需要实现和评估它们的操作,而无需直接在解释器中处理这些值。
另一个好处是使用此方法,如果用户尝试运行错误的脚本(例如尝试将BoolVar添加到IntVar),则会在解释器中抛出异常。
也许您甚至可以在抽象Var类中使用默认的操作实现:
public Var add(Var var)
{
throw new OperationNotSupportedException(); // no other types can be added to an IntValue so throw an exception
}
只有在安全使用操作时才覆盖/过载。
当你在这里说“阅读内容”时,可能至少需要在某个时刻以统一的方式处理某个类型实例的内容,如果这仅仅是为了输出,那么为什么不只是一个抽象的'toString()'方法?如果出于某些其他目的而不是输出,那么你有什么目的不能只使用其他一些toX()方法并以相同的方式处理每个类型实例?
我意识到这并没有直接回答你的问题,而是提出了一种不同的方法,希望完全避免这个问题,这可能完全没有用,因为我可能对你想要实现的目标做了一些愚蠢的假设。 o已经看到了问题的更多背景,但我希望它仍然有用。
如果这没有用,那么请提供更多信息,我会尝试多一点帮助,因为我不能建议继续当前的方法,但我不确定除此之外还有什么建议。
编辑:等等,我的坏,我没有正确地阅读这个问题。这不是解释器,而是生成器。什么样的发电机?什么语言的脚本生成器?那些,这些可能不是重要问题,但现在我已经重新阅读了这个问题,我意识到我对你需要实现的目标并不是很了解。
我仍然认为封装是比访问者模式更好的选择,一般来说:)。当然,除非有某些原因需要添加行为,这些行为可以对任何变量进行操作,使得行为无法通过Var提供的接口从已经附加到每个变量的行为构建...可能会有什么行为这是?对于输出,您肯定需要以所有这些变量共有的格式读取每个变量,为什么不仅仅是toString(),toSomething(),toAnotherThing()等。
答案 3 :(得分:0)
我的建议是使用Visitor
模式。该算法将放在Visitor
而不是对象Var
(和子类)中。
public class Var {
public void accept(VarVisitor visitor) {
visitor.visit(this);
}
}
访问者
public interface VarVisitor {
public void visit(FloatVar var);
public void visit(IntVar var);
public void visit(StringVar var);
public void visit(BoolVar var);
//...etc.
public Object getValue();
}
VisitorImpl
public class VarVisitorImpl implements VarVisitor {
private Object value;
@Override
public Object getValue() {
return value;
}
@Override
public void visit(FloatVar var) {
}
@Override
public void visit(IntVar var) {
}
@Override
public void visit(StringVar var) {
}
@Override
public void visit(BoolVar var) {
}
}
我希望这可以让您了解自己想要达到的目标。