Tolk (designmönster)

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 5 april 2017; kontroller kräver 12 redigeringar .
Tolk
tolk
Sorts beteendemässiga
Ändamål löser ett ofta uppstått problem med reservation för ändringar
Beskrivs i Design Patterns Ja

En tolk är ett  beteendedesignmönster som löser en ofta förekommande, men kan förändras, uppgift. Även känt som Little (Small) Language

Problem

Det finns en ofta förekommande uppgift som kan ändras.

Lösning

Skapa en tolk som löser detta problem.

Fördelar

Grammatiken blir lätt att utöka och ändra, implementeringarna av klasserna som beskriver noderna i det abstrakta syntaxträdet är likartade (lättkodade). Du kan enkelt ändra hur uttryck utvärderas.

Nackdelar

Att upprätthålla en grammatik med ett stort antal regler är svårt.

Exempel

Uppgiften att söka efter strängar efter mönster kan lösas genom att skapa en tolk som definierar språkets grammatik. "Klienten" bygger en mening i form av ett abstrakt syntaxträd, i vars noder det finns objekt av klasserna "TerminalExpression" och "NonterminalExpression" (rekursiv), sedan initierar "Client" sammanhanget och anropar Parse( sammanhang) operation. Varje nod av typen "NonterminalExpression" definierar en Parse-operation för varje underuttryck. För klassen "NonTerminalExpression" bestämmer Parse-operationen basen för rekursionen. "AbstractExpression" definierar operationen Parse abstrakt som är gemensam för alla noder i det abstrakta syntaxträdet. "Kontext" innehåller information som är global för tolken.

C#

Källtext i C# använder System ; använder System.Collections ; namnutrymme DoFactory.GangOfFour.Interpreter.Structural { class Program { static void Main () { var context = new Context (); var input = new MyExpression (); var expression = new OrExpression { Left = new EqualsExpression { Left = input , Right = new MyExpression { Value = "4" } }, Right = new EqualsExpression { Left = input , Right = new MyExpression { Value = "four" } } } ; // Utdata: sann input . Värde = "fyra" ; uttryck . Tolka ( kontext ); Konsol . WriteLine ( context.result.pop ( ) ) ; _ // Utdata: falsk input . Värde = "44" ; uttryck . Tolka ( kontext ); Konsol . WriteLine ( context.result.pop ( ) ) ; _ } } class Context { public Stack < string > Result = new Stack < string >(); } gränssnitt Uttryck { void Tolka ( Kontextkontext ) ; } abstrakt klass OperatorExpression : Expression { public Expression Left { private get ; set ; } offentligt uttryck Rätt { privat ; set ; } public void Tolka ( Kontextkontext ) { Vänster . _ Tolka ( kontext ); sträng leftValue = sammanhang . resultat . pop (); Rätt . Tolka ( kontext ); sträng rightValue = sammanhang . resultat . pop (); DoInterpret ( kontext , leftValue , rightValue ); } skyddad abstrakt void DoInterpret ( Kontextkontext , sträng leftValue , sträng rightValue ) ; } class EqualsExpression : OperatorExpression { protected override void DoInterpret ( Context context , string leftValue , string rightValue ) { context . resultat . Push ( leftValue == rightValue ? "true" : "false" ); } } class OrExpression : OperatorExpression { protected override void DoInterpret ( Context context , string leftValue , string rightValue ) { context . resultat . Push ( leftValue == "true" || rightValue == "true" ? "true" : "false" ); } } class MyExpression : Expression { public string Value { private get ; set ; } public void Tolka ( Kontext sammanhang ) { sammanhang . resultat . Tryck ( Värde ); } } }

Python

Källkod i Python __doc__ = ''' Ett system för att utvärdera och manipulera booleska uttryck. Exempel från Gang of Four - "Design Patterns: Elements of Reusable Object-Oriented Software" ''' från abc import ABCMeta , abstraktmetod class Context : """ Runtime-kontext för tolken """ def __init__ ( själv , variabler : dict = {}) -> Ingen : """ Konstruktör. :param variabler: en ordbok över matchningar mellan variabelnamn och deras värden " "" self ._variables = variables class ContextException ( Undantag ): """ Undantag kastas i händelse av felaktigt arbete med detta klass """ pass def lookup ( self , name : str ) -> bool : """ Får värdet på en variabel efter dess namn :param namn: variabelnamn """ om namn i själv . _variabler : returnerar själv . _variabler [ namn ] höjer själv . ContextException ( 'Okänd variabel {} ' . format ( namn )) def assign ( self , name : str , value : bool ) -> None : """ Tilldelar ett värde till en variabel med dess namn :paramnamn: variabelnamn :paramvärde: variabelvärde " "" self ._variables [ name ] = värde class BooleanExp ( metaclass = ABCMeta ): """ Abstrakt booleskt uttryck """ @abstractmethod def utvärdera ( själv , sammanhang : Kontext ) -> bool : """ Få resultatet av det boolska uttrycket """ pass klass ConstantExp ( BooleanExp ): """ Boolesk konstant """ def __init__ ( själv , värde : bool ): """ Konstruktör. :param värde: uttrycksvärde (Sant eller Falskt) "" " self ._value = värde def utvärdera ( själv , sammanhang : Kontext ): returnera själv . _värde klass VariableExp ( BooleanExp ): """ Boolesk variabel (värdet på variabler lagras i tolkkontextobjektet) """ def __init__ ( själv , namn : str ) -> Ingen : """ Konstruktör. :param namn: variabelnamn " "" self ._name = namn def utvärdera ( själv , sammanhang : Kontext ) -> bool : returnera sammanhang . uppslag ( self . _name ) klass BinaryOperationExp ( BooleanExp , metaclass = ABCMeta ): """ Abstrakt klass för binära logiska operationer """ def __init__ ( själv , vänster : BooleanExp , höger : BooleanExp ) -> Ingen : """ Konstruktör. :param vänster: vänster operand :param höger: höger operand " " " själv ._left = vänster själv ._right = höger klass AndExp ( BinaryOperationExp ): """ Konjunktion """ def utvärdera ( själv , sammanhang : Kontext ) -> bool : returnera själv . _vänster . utvärdera ( sammanhang ) och själv . _höger . utvärdera ( sammanhang ) klass OrExp ( BinaryOperationExp ): """ Disjunktion """ def utvärdera ( själv , sammanhang : Kontext ) -> bool : returnera själv . _vänster . utvärdera ( sammanhang ) eller själv . _höger . utvärdera ( sammanhang ) klass NotExp ( BooleanExp ): """ Negativ """ def __init__ ( själv , operand : BooleanExp ) -> Ingen : """ Konstruktör. :param operand: operand som operationen """ tillämpas på själv _operand = operand def utvärdera ( själv , sammanhang : Kontext ) -> bool : returnera inte själv . _operand . utvärdera ( sammanhang ) def execute_test ( context : Context , x : bool , y : bool ) -> None : """ En funktion för att utföra tester på vår """ kontexttolkare . tilldela ( 'x' , x ) sammanhang . tilldela ( 'y' , y ) uttryck = OrExp ( # (True och x) eller (y och (inte x)) AndExp ( ConstantExp ( True ), VariableExp ( 'x' )), AndExp ( VariableExp ( 'y' ) , NotExp ( VariableExp ( 'x' ))) ) print ( expression . evaluate ( context )) if __name__ == '__main__' : print ( 'OUTPUT:' ) context = Context () execute_test ( context , True , False ) execute_test ( context , False , True ) execute_test ( context , False , False ) ''' OUTPUT: Sant Sant Falskt '''

PHP

PHP källkod <?php /** * Exempel på tolkmönster med komposition */ abstrakt klass Uttryck { privat statisk $_count = 0 ; privat $_key = null ; public abstract function interpret ( InterpreterContext $context ); public function getKey () { if ( ! isset ( $this -> _key ) ) { self :: $_count ++ ; $this -> _key = self :: $_count ; } returnera $this -> _key ; } } class LiteralExpression utökar uttryck { privat $_value = null ; offentlig funktion __construct ( $värde ) { $this -> _value = $värde ; } public function interpret ( InterpreterContext $context ) { $context -> replace ( $this , $this -> _value ); } } class VariableExpression utökar Expression { privat $_name = null ; privat $_val = null ; offentlig funktion __construct ( $namn , $val = null ) { $this -> _name = $namn ; $this -> _val = $val ; } public function interpret ( InterpreterContext $context ) { if ( ! is_null ( $this -> _val ) ) $context -> replace ( $this , $this -> _val ); } offentlig funktion setValue ( $värde ) { $this -> _val = $värde ; } public function getKey () { return $this -> _name ; } } abstrakt klass OperatorExpression utökar uttryck { skyddad $leftoperand = null ; skyddad $rightoperand = null ; public function __construct ( Uttryck $vänsteroperand , Uttryck $högeroperand ) { $this -> leftoperand = $vänsteroperand ; $this -> högeroperand = $högeroperand ; } public function interpret ( InterpreterContext $context ) { $this -> leftoperand -> interpret ( $context ); $this -> högeroperand -> tolka ( $kontext ); $resultleft = $context -> lookup ( $this -> leftoperand ); $resultright = $context -> lookup ( $this -> rightoperand ); $this -> doInterpret ( $context , $resultleft , $resultright ); } skyddad abstrakt funktion doInterpret ( InterpreterContext $context , $resultleft , $resultright ); } class EqualsExpression utökar OperatorExpression { skyddad funktion doInterpret ( InterpreterContext $context , $resultleft , $resultright ) { $context -> replace ( $this , $resultleft == $resultright ); } } class BooleanOrExpression utökar OperatorExpression { skyddad funktion doInterpret ( InterpreterContext $context , $resultleft , $resultright ) { $context -> replace ( $this , $resultleft || $resultright ); } } class BooleanAndExpression utökar OperatorExpression { skyddad funktion doInterpret ( InterpreterContext $context , $resultleft , $resultright ) { $context -> replace ( $this , $resultleft && $resultright ); } } class InterpreterContext { privat $_expressionstore = array (); public function replace ( Uttryck $exp , $value ) { $this -> _expressionstore [ $exp -> getKey ()] = $värde ; } public function lookup ( Uttryck $exp ) { return $this -> _expressionstore [ $exp -> getKey ()]; } } $context = new InterpreterContext (); $input = new VariableExpression ( 'input' ); $statement = new BooleanOrExpression ( nytt EqualsExpression ( $input , new LiteralExpression ( "fyra" ) ), nytt EqualsExpression ( $input , new LiteralExpression ( "4" ) ) ); foreach ( array ( "fyra" , "4" , "52" ) ​​som $värde ) { $input -> setValue ( $värde ); skriv ut " { $värde } :<br>" ; $statement -> tolka ( $kontext ); skriva ut $context -> lookup ( $statement ) ? "Meets<br><br>" : "Stämmar inte<br><br>" ; } ?>

Se även