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.
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 få ; 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 );
}
}
}
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 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