Le livre du Dr Yan Hong "JAVA and Patterns" commence par une description du modèle Interpreter :
Le modèle d’interprète est un modèle de comportement pour les classes. Étant donné une langue, le modèle interpréteur définit une représentation de sa grammaire et fournit un interprète. Les clients peuvent utiliser cet interprète pour interpréter des phrases dans cette langue.
La structure du mode interprète
Prenons un système schématique comme exemple pour discuter de la structure du mode interpréteur. Le schéma de structure du système est le suivant :
Les rôles impliqués dans le modèle sont les suivants :
(1) Rôle d'expression abstraite (Expression) : déclarez une interface abstraite que tous les rôles d'expression concrète doivent implémenter. Cette interface est principalement une méthode perform(), appelée opération d’interprétation.
(2) Rôle d'expression terminale : implémente l'interface requise par le rôle d'expression abstraite, principalement une méthode perform() ; chaque symbole terminal de la grammaire a une expression terminale spécifique qui lui correspond. Par exemple, il existe une formule simple R=R1+R2, dans laquelle R1 et R2 sont des symboles terminaux, et l'interpréteur correspondant qui analyse R1 et R2 est une expression terminale.
(3) Rôle de l'expression non terminale : chaque règle de la grammaire nécessite une expression non terminale spécifique. Les expressions non terminales sont généralement des opérateurs ou d'autres mots-clés dans la grammaire, tels que des formules. Dans R=R1+R2, "+" est un symbole non terminal. , et l'interpréteur qui analyse "+" est une expression de symbole non terminale.
(4) Rôle contextuel : La tâche de ce rôle est généralement de stocker les valeurs spécifiques correspondant à chaque symbole terminal dans la grammaire. Par exemple, R=R1+R2, nous attribuons une valeur de 100 à R1 et une valeur de. 200 à R2. Ces informations doivent être stockées dans le rôle d'environnement. Dans de nombreux cas, il suffit d'utiliser Map pour agir en tant que rôle d'environnement.
Afin d'illustrer l'implémentation du mode interpréteur, voici la grammaire la plus simple et l'implémentation correspondante du mode interpréteur, qui consiste à simuler le fonctionnement et l'évaluation d'expressions booléennes dans le langage Java.
Les symboles terminaux dans ce langage sont des variables booléennes, c'est-à-dire les constantes vraies et fausses. Les expressions non terminales incluent les expressions booléennes telles que les opérateurs et, ou et non. Cette grammaire simple est la suivante :
Copiez le code comme suit :
Expression ::= Variable |
Et ::= Expression 'ET' Expression
Ou ::= Expression 'OU' Expression
Pas ::= Expression 'NON'
Variable ::= n'importe quel identifiant
Constante ::= 'vrai' |
Le schéma structurel du mode interpréteur est le suivant :
code source
rôle d'expression abstraite
Copiez le code comme suit :
classe abstraite publique Expression {
/**
* Sous réserve de l'environnement, cette méthode interprète toute expression donnée
*/
interprétation booléenne abstraite publique (Context ctx);
/**
* Vérifiez si deux expressions sont structurellement identiques
*/
public abstrait booléen égal (Objet obj);
/**
* Renvoie le code de hachage de l'expression
*/
public abstrait int hashCode();
/**
* Convertir l'expression en chaîne
*/
public abstrait String toString();
}
Un objet Constant représente une constante booléenne
Copiez le code comme suit :
la classe publique Constant étend l'expression {
valeur booléenne privée ;
constante publique (valeur booléenne) {
this.value = valeur ;
}
@Outrepasser
public booléen égal (Objet obj) {
if(obj != null && obj instanceof Constant){
return this.value == ((Constante)obj).value;
}
renvoie faux ;
}
@Outrepasser
public int hashCode() {
renvoie this.toString().hashCode();
}
@Outrepasser
interprétation booléenne publique (Context ctx) {
valeur de retour ;
}
@Outrepasser
chaîne publique toString() {
return new Boolean(value).toString();
}
}
Un objet Variable représente une variable nommée. Le code est le suivant :
La variable de classe publique étend l'expression {
nom de chaîne privé ;
Variable publique (nom de la chaîne) {
this.name = nom ;
}
@Outrepasser
public booléen égal (Objet obj) {
if(obj != null && obj instanceof Variable)
{
renvoie this.name.equals(
((Variable)obj).nom);
}
renvoie faux ;
}
@Outrepasser
public int hashCode() {
renvoie this.toString().hashCode();
}
@Outrepasser
chaîne publique toString() {
renvoyer le nom ;
}
@Outrepasser
interprétation booléenne publique (Context ctx) {
return ctx.lookup(this);
}
}
La classe And représente l'opération logique « ET », qui représente l'opération consistant à donner une nouvelle expression booléenne à partir de deux expressions booléennes via l'opération logique « ET ».
Copiez le code comme suit :
classe publique et étend l'expression {
expression privée gauche, droite ;
public Et (Expression à gauche, Expression à droite){
this.left = gauche ;
this.right = droite ;
}
@Outrepasser
public booléen égal (Objet obj) {
if(obj != null && obj instanceof And)
{
return left.equals(((And)obj).left) &&
right.equals(((Et)obj).right);
}
renvoie faux ;
}
@Outrepasser
public int hashCode() {
renvoie this.toString().hashCode();
}
@Outrepasser
interprétation booléenne publique (Context ctx) {
return left.interpret(ctx) && right.interpret(ctx);
}
@Outrepasser
chaîne publique toString() {
return "(" + left.toString() + " AND " + right.toString() + ")";
}
}
La classe Or représente l'opération logique « OU », qui représente l'opération consistant à donner une nouvelle expression booléenne à partir de deux expressions booléennes via l'opération logique « OU ».
Copiez le code comme suit :
classe publique Ou étend l'Expression {
expression privée gauche, droite ;
public Ou(Expression à gauche, Expression à droite){
this.left = gauche ;
this.right = droite ;
}
@Outrepasser
public booléen égal (Objet obj) {
if(obj != null && obj instanceof Ou)
{
return this.left.equals(((Or)obj).left) && this.right.equals(((Or)obj).right);
}
renvoie faux ;
}
@Outrepasser
public int hashCode() {
renvoie this.toString().hashCode();
}
@Outrepasser
interprétation booléenne publique (Context ctx) {
return left.interpret(ctx) || right.interpret(ctx);
}
@Outrepasser
chaîne publique toString() {
return "(" + left.toString() + " OR " + right.toString() + ")";
}
}
La classe Not représente l'opération logique « non », qui représente l'opération consistant à donner une nouvelle expression booléenne à partir d'une expression booléenne via l'opération logique « non » Copiez le code comme suit :
classe publique N'étend pas l'expression {
expression privée exp;
public Non (Expression exp){
ceci.exp = exp;
}
@Outrepasser
public booléen égal (Objet obj) {
if(obj != null && obj instanceof Not)
{
retourner exp.equals(
((Pas)obj).exp);
}
renvoie faux ;
}
@Outrepasser
public int hashCode() {
renvoie this.toString().hashCode();
}
@Outrepasser
interprétation booléenne publique (Context ctx) {
return !exp.interpret(ctx);
}
@Outrepasser
chaîne publique toString() {
return "(Pas " + exp.toString() + ")" ;
}
}
La classe Context définit un mappage des variables aux valeurs booléennes
Copiez le code comme suit :
contexte de classe publique {
private Map<Variable,Boolean> map = new HashMap<Variable,Boolean>();
public void assign(Variable var, valeur booléenne){
map.put(var, new Boolean(value));
}
la recherche booléenne publique (Variable var) lance IllegalArgumentException {
Valeur booléenne = map.get(var);
si(valeur == null){
lancer une nouvelle IllegalArgumentException();
}
valeur de retour.booleanValue();
}
}
Classe de clients
Copiez le code comme suit :
Client de classe publique {
public static void main (String[] arguments) {
Contexte ctx = nouveau Contexte();
Variable x = nouvelle variable("x");
Variable y = nouvelle variable("y");
Constante c = nouvelle Constante (vrai) ;
ctx.assign(x, false);
ctx.assign(y, vrai);
Expression exp = new Or(new And(c,x) , new And(y,new Not(x)));
System.out.println("x=" + x.interpret(ctx));
System.out.println("y=" + y.interpret(ctx));
System.out.println(exp.toString() + "=" + exp.interpret(ctx));
}
}
Les résultats en cours d'exécution sont les suivants :