2

假设我想将阿拉伯数字 (1+2) 或罗马数字 (I+II) 相加,并使用如下所示的解释器模式:

(代码来自这里:https ://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Design_Patterns#Interpreter )

struct Expression {
    virtual int interpret() = 0;
};

class ArabicNumber : public Expression {
private:
    int number;
public: 
    ArabicNumber(int number)       { this->number = number; }
    int interpret(Map variables)  { return number; }
}

class RomanNumber : public Expression {
private:
    string number;
public: 
    RomanNumber(string number)       { this->number = number; }
    int interpret(Map variables)  {
        //somehow convert the roman number string to an int
    }
}

class Plus : public Expression {
  Expression* leftOperand;
   Expression* rightOperand;
public: 
    Plus(Expression* left, Expression* right) { 
        leftOperand = left; 
        rightOperand = right;
    }
    ~Plus(){ 
        delete leftOperand;
        delete rightOperand;
    }

    int interpret(Map variables)  { 
        return leftOperand->interpret(variables) + rightOperand->interpret(variables);
    }
};

如何确保正确处理错误查询(1+II)?我能想到的唯一解决方案是以某种方式使用强制转换,但这听起来不像是一个优雅的解决方案。还是不应该那样使用模式?

当然,一种选择是为此编写两个单独的函数,但我很好奇它是否可以在一个函数中完成,因为我想将此模式用于更复杂的上下文无关语法。

编辑:我的问题也在这里描述。我引用相关部分:

然而,引入一种语言及其附带的语法也需要对拼写错误的术语或错位的语法元素进行相当广泛的错误检查。

所以我的主要问题是:如何最好地设计广泛的错误检查?

4

1 回答 1

1

您真的只想允许添加罗马数字或阿拉伯数字,而不是混合吗?如果混合可以,那么您的代码就可以工作(假设您为罗马转整数编写了实际的解析代码)。如果您不想允许混合,则需要在对 Plus() 中的两个参数调用解释之前添加一个验证步骤。

例如,您可以dynamic_cast<ArabicNumber>同时使用两个操作数,如果其中一个为 NULL,则失败,如果两者均为 NULL,请尝试dynamic_cast<RomanNumber>改用。通常测试一个类的类型是一种代码味道,但在这里你正在验证,所以没关系。

另一种方法是给每个方法Expression一个CanBeConvertedToType()方法,然后在该函数中有一个 switch 语句,该语句将表示给定类型的常量检查为给定结果的类型Expression。这对未来更加安全,因为它允许您拥有Expression所有返回相同类型的不同子类,而无需更改类型检查代码来检查每个在添加新类时是否有效。

于 2016-01-14T12:39:54.967 回答