Définition: Compte tenu d'une langue, définissez une représentation de sa grammaire et définissez un interprète qui utilise la représentation pour interpréter les phrases dans la langue.
Type: modèle de comportement
Diagramme de classe:
Le mode interprète est un mode relativement rarement utilisé, et je n'ai jamais utilisé ce mode auparavant. Jetons un coup d'œil au mode interprète.
Structure du mode interprète
Interprète abstrait: Déclarez une interface abstraite (ou classe abstraite) à laquelle toutes les expressions concrètes doivent être mises en œuvre. L'interface est principalement une méthode d'interprétation (), appelée opération d'explication. La tâche d'interprétation spécifique est effectuée par ses différentes classes d'implémentation, et l'interprète spécifique est complété par l'interprète Terminator Terminalexpression et l'interprète non terminal respectivement non terminalexpression.
Expression du terminateur: met en œuvre les opérations d'interprétation associées aux éléments de la grammaire. Habituellement, il n'y a qu'une seule expression de terminateur dans un modèle d'interprète, mais il y a plusieurs instances, correspondant à différents terminateurs. La moitié du terminateur est une unité de fonctionnement de la grammaire. Par exemple, il existe une formule simple R = R1 + R2, où R1 et R2 sont des terminateurs, et les interprètes correspondants qui analysent R1 et R2 sont des terminateurs.
Expression non terminale: chaque règle de la grammaire correspond à une expression non terminale. Les expressions non terminales sont généralement des opérateurs ou d'autres mots clés de la grammaire. Par exemple, dans la formule R = R1 + R2, + est un caractère non terminal, et l'interprète de l'analyse + est un caractère non terminal. Les expressions non terminales augmentent en fonction de la complexité de la logique et, en principe, chaque règle de grammaire correspond à une expression non terminale.
Rôle de l'environnement: La tâche de ce rôle est généralement utilisée pour stocker les valeurs spécifiques correspondant à chaque terminateur de la grammaire, tels que R = R1 + R2. Nous attribuons 100 à R1 et 200 à R2. Ces informations doivent être stockées dans le rôle de l'environnement. Dans de nombreux cas, nous utilisons la carte pour agir comme le rôle de l'environnement est suffisant.
exemple
Donnons un exemple d'addition, de soustraction, de multiplication et de division. L'idée d'implémentation provient de l'exemple de "Java et Pattern". Les fonctions de chaque rôle sont mises en œuvre conformément aux spécifications mentionnées ci-dessus.
// Contexte (Environnement) Rôle, utilisez HashMap pour stocker les valeurs numériques correspondant à la classe Variables Context {Private Map ValuMap = new HashMap (); public void addValue (variable x, int y) {entier yi = nouveau entier (y); ValuMap.put (x, yi); } public int lookupValue (variable x) {int i = ((Integer) valuemap.get (x)). intValue (); retour i; }} // Rôle d'expression abstrait, vous pouvez également utiliser des interfaces pour implémenter l'expression de la classe abstraite {public abstract int interprèter (Context Con); } // Terminator Expression Classe de rôle La constante étend l'expression {private int i; Public constante (int i) {this.i = i; } public int interpréter (Context Con) {return i; }} La variable de classe étend l'expression {public int interpréter (Context Con) {// Il s'agit d'un objet variable qui appelle la méthode d'interprétation return con.lookupValue (this); }} // La classe de rôles d'expression non terminatrice ajoute l'expression {Expression privée gauche, droite; Adresse publique (expression gauche, expression droite) {this.left = Left; this.Right = droite; } public int interpréter (Context Con) {return Left.interpret (con) + right.interpret (con); }} Classe Soustraire étend l'expression {Expression privée gauche, droite; public soustraire (expression gauche, expression droite) {this.left = gauche; this.Right = droite; } public int interpréter (Context Con) {return Left.interpret (con) - droite.interpret (con); }} La classe Multiply étend l'expression {Expression privée gauche, droite; public multiply (expression gauche, expression droite) {this.left = gauche; this.Right = droite; } public int interpréter (Context Con) {return Left.interpret (con) * right.interpret (con); }} La division de classe étend l'expression {Expression privée gauche, droite; Division publique (expression gauche, expression droite) {this.left = gauche; this.Right = droite; } public int interpréter (Context Con) {try {return Left.interpret (con) / droite.interpret (con); } catch (arithmeticexception ae) {System.out.println ("divorc est 0!"); retour -11111; }}} // tester le programme, calculer (a * b) / (a-b + 2) Test de classe publique {Expression statique privée ex; Contexte statique privé Con; public static void main (String [] args) {con = new Context (); // Définir les variables et les constantes variables a = nouvelle variable (); Variable b = nouvelle variable (); Constant C = nouvelle constante (2); // attribue la variable con.addvalue (a, 5); con.addvalue (b, 7); // opération, nous analysons la structure de la phrase nous-mêmes, construisons ex = nouvelle division (nouveau multiply (a, b), nouveau add (nouveau soustraire (a, b), c)); System.out.println ("Le résultat de l'opération est:" + ex.interpret (con)); }} Avantages et inconvénients du mode interprète
L'interprète est un simple outil d'analyse de syntaxe. Son avantage le plus significatif est son extensibilité. La modification des règles de syntaxe nécessite uniquement de modifier les caractères non terminaux correspondants. Si vous développez la syntaxe, il vous suffit d'ajouter un caractère non terminal.
Cependant, le modèle d'interprète entraînera l'expansion de la classe et chaque syntaxe doit produire une expression non terminale. Lorsque les règles de syntaxe sont relativement complexes, un grand nombre de fichiers de classe peuvent être générés, ce qui demande beaucoup de problèmes à la maintenance. Dans le même temps, puisque la méthode d'appel récursive est adoptée, chaque expression non terminale ne se soucie que des expressions liées à elle-même. Chaque expression doit connaître le résultat final et doit être récursive. Qu'il s'agisse d'une langue orientée objet ou d'une langue axée sur le processus, la récursivité est une manière non recommandée. En raison de l'utilisation de nombreuses boucles et de la récursivité, l'efficacité est un problème qui ne peut être ignoré. Surtout lorsqu'il est utilisé pour interpréter un complexe d'analyse, une longue syntaxe, l'efficacité est insupportable.
Scénarios applicables pour le mode interprète
Le mode interprète peut être utilisé dans les cas suivants:
Il existe une règle de syntaxe simple, comme une instruction SQL. Si nous devons effectuer une conversion RM basée sur les instructions SQL, nous pouvons utiliser le modèle d'interprète pour interpréter l'instruction.
Certains problèmes répétitifs, tels que les quatre opérations d'addition, de soustraction, de multiplication et de division, mais les formules sont différentes à chaque fois. Parfois, c'est un + BC * D, parfois c'est un CD * B +, etc. Les formules changent en constante évolution, mais elles sont toutes connectées par les quatre caractères non terminaux d'addition, de soustraction, de multiplication et de division. Pour le moment, nous pouvons utiliser le mode interprète.
Choses à noter
Le mode interprète est vraiment un mode relativement rarement utilisé car il est trop gênant pour le maintenir. Imaginez que si un tas d'interprètes non terminaux ne connaissent pas les règles de la grammaire à l'avance, ou si la grammaire est particulièrement simple, il sera difficile de comprendre sa logique. Le mode interprète est rarement utilisé dans le développement réel du système car il peut entraîner des problèmes tels que l'efficacité, les performances et la maintenance.