Tulkki (suunnittelukuvio)
Kokeneet kirjoittajat eivät ole vielä tarkistaneet sivun nykyistä versiota, ja se voi poiketa merkittävästi 5. huhtikuuta 2017 tarkistetusta
versiosta . tarkastukset vaativat
12 muokkausta .
Tulkki |
---|
tulkki |
Tyyppi |
käyttäytymiseen |
Tarkoitus |
ratkaisee usein kohdattavan ongelman, joka voi muuttua |
Kuvattu suunnittelukuvioissa |
Joo |
Tulkki on käyttäytymismalli , joka ratkaisee usein kohtaaman , mutta muuttuvan tehtävän. Tunnetaan myös nimellä Little (Small) Language
Ongelma
Siellä on usein esiintyvä tehtävä, joka voi muuttua.
Ratkaisu
Luo tulkki, joka ratkaisee tämän ongelman.
Edut
Kielioppi on helppo laajentaa ja muuttaa, abstraktin syntaksipuun solmuja kuvaavien luokkien toteutukset ovat samanlaisia (helposti koodattuja). Voit helposti muuttaa tapaa, jolla lausekkeet arvioidaan.
Haitat
Kieliopin ylläpitäminen suurella määrällä sääntöjä on vaikeaa.
Esimerkki
Merkkijonojen etsiminen kuvion mukaan voidaan ratkaista luomalla tulkki, joka määrittelee kielen kieliopin. "Client" rakentaa lauseen abstraktin syntaksipuun muodossa, jonka solmuissa on objekteja luokista "TerminalExpression" ja "NonterminalExpression" (rekursiivinen), sitten "Client" alustaa kontekstin ja kutsuu Parse( konteksti) -toiminto. Jokainen "NonterminalExpression"-tyypin solmu määrittää jäsennystoiminnon kullekin alilausekkeelle. "NonTerminalExpression"-luokassa jäsennystoiminto määrittää rekursion perustan. "AbstractExpression" määrittää abstraktin jäsennystoiminnon, joka on yhteinen kaikille abstraktin syntaksipuun solmuille. "Konteksti" sisältää tulkin globaalia tietoa.
Lähdeteksti C#
käyttäen System ;
käyttämällä System.Collections -ohjelmaa ;
nimiavaruus DoFactory.GangOfFour.Interpreter.Structural
{
class Program
{
static void Main ()
{
var konteksti = new Context ();
var input = uusi MyExpression ();
var lauseke = uusi OrExpression
{
Vasen = uusi EqualsExpression
{
Vasen = syöte ,
Oikea = uusi OmaLauseke { Arvo = "4" }
},
Oikea = uusi EqualsExpression
{
Vasen = input ,
Oikea = uusi Omalauseke { Arvo = "neljä" }
}
} ;
// Tulostus: true
input . Arvo = "neljä" ;
ilmaisua . tulkita ( konteksti );
konsoli . WriteLine ( konteksti.tulos.pop ( ) ) ; _
// Lähtö: väärä
syöttö . Arvo = "44" ;
ilmaisua . tulkita ( konteksti );
konsoli . WriteLine ( konteksti.tulos.pop ( ) ) ; _ } }
class Konteksti
{
public Pino < merkkijono > Tulos = new Pino < merkkijono >();
}
käyttöliittymä Lauseke
{
void Tulkita ( kontekstikonteksti ) ;
}
abstrakti luokka OperatorExpression : Lauseke
{
public Expression Left { private get ; asettaa ; }
public Expression Right { private get ; asettaa ; }
public void Tulkita ( kontekstikonteksti ) { Vasen . _ tulkita ( konteksti ); merkkijono leftValue = konteksti . tulos . pop ();
Oikein . tulkita ( konteksti );
string rightValue = konteksti . tulos . pop ();
DoIninterpret ( konteksti , leftValue , rightValue );
}
suojattu abstrakti void DoInterpret ( kontekstikonteksti , merkkijono leftValue , merkkijono rightValue ) ; }
class EqualsExpression : OperatorExpression
{
suojattu ohitus void DoInterpret ( kontekstikonteksti , merkkijono leftValue , string rightValue ) { konteksti . _ tulos . Push ( leftValue == rightValue ? "true" : "false" ); } }
class OrExpression : OperatorExpression
{
suojattu ohitus void DoInterpret ( kontekstikonteksti , merkkijono leftValue , string rightValue ) { konteksti . _ tulos . Push ( leftValue == "tosi" || rightValue == "tosi" ? "tosi" : "false" ); } }
class MyExpression : Lauseke
{
public string Arvo { private get ; asettaa ; }
public void Tulkita ( kontekstikonteksti ) { konteksti . _ tulos . Työnnä ( arvo ); } } }
Lähdekoodi Pythonissa
__doc__ = '''
Järjestelmä loogisten lausekkeiden arviointiin ja käsittelyyn. Esimerkki
Gang of Fourista - "Design Patterns: Elements of Reusable Object Oriented Software"
'''
abc importista ABCMeta , abstrakti menetelmä
luokan konteksti :
"""
Tulkin
"" " ajonaikainen konteksti
def __init__ ( itse , muuttujat : dict = {}) -> Ei mitään :
"""
Rakentaja.
:param variables: sanakirja vastaavuuksista muuttujien nimien ja niiden arvojen välillä
" ""
itse ._variables = muuttujat
luokka ContextException ( Poikkeus ):
"""
Poikkeus tehdään virheellisen työn yhteydessä tämän luokan
"""
passilla
def lookup ( itse , nimi : str ) -> bool :
"""
Hakee muuttujan arvon sen nimen mukaan
:param nimi: muuttujan nimi
"""
jos nimi itsessä . _variables : palauttaa itsensä . _muuttujat [ nimi ] nostavat itsensä . ContextException ( ' Tuntematon muuttuja {} ' . muoto ( nimi ))
def assign ( itse , nimi : str , arvo : bool ) -> Ei mitään :
"""
Määrittää muuttujalle arvon sen nimen perusteella
:param nimi: muuttujan nimi
:param arvo: muuttujan arvo
" ""
itse ._variables [ nimi ] = arvo
luokka BooleanExp ( metaluokka = ABCMeta ):
"""
Abstrakti boolen lauseke
"""
@abstractmethod
def arvo _ _ _ _ _ _ _ _ _ _ _
_
_
_
luokka ConstantExp ( BooleanExp ):
"""
Boolen vakio
"""
def __init__ ( itse , arvo : bool ):
"""
Rakentaja.
:param arvo: lausekkeen arvo (tosi tai epätosi)
""
" itse ._value = arvo
def arvioida ( itse , konteksti : konteksti ):
palauttaa itse . _arvo
luokka VariableExp ( BooleanExp ):
"""
Boolen muuttuja (muuttujien arvot tallennetaan tulkin kontekstiobjektiin)
"""
def __init__ ( itse , nimi : str ) -> Ei mitään :
"""
Rakentaja.
:param nimi: muuttujan nimi
" ""
itse ._name = nimi
def arvioida ( itse , konteksti : konteksti ) -> bool :
palauttaa kontekstin . haku ( itse . _nimi )
luokka BinaryOperationExp ( BooleanExp , metaclass = ABCMeta ):
"""
Abstrakti luokka binaarisille loogisille operaatioille
"""
def __init__ ( itse , vasen : BooleanExp , oikea : BooleanExp ) -> Ei mitään :
"""
Rakentaja.
:param vasen: vasen operandi
:param right: oikea operandi
" "
" itse ._left = vasen itse ._right = oikea
luokka AndExp ( BinaryOperationExp ):
"""
Konjunktio
"""
def arvioida ( itse , konteksti : konteksti ) -> bool :
palauttaa itsensä . _vasen . arvioida ( kontekstia ) ja itseään . _oikein . arvioida ( konteksti )
luokka OrExp ( BinaryOperationExp ):
"""
Disjunktio
"""
def arvioida ( itse , konteksti : konteksti ) -> bool :
palauttaa itsensä . _vasen . arvioida ( konteksti ) tai itseään . _oikein . arvioida ( konteksti )
luokka NotExp ( BooleanExp ):
"""
Negatiivinen
"""
def __init__ ( itse , operandi : BooleanExp ) -> Ei mitään :
"""
Rakentaja.
:param operandi: operandi, johon
"""
-toimintoa sovelletaan itse _operand = operandi
def arvioida ( itse , konteksti : konteksti ) -> bool :
palauttaa ei itse . _operandi . arvioida ( konteksti )
def execute_test ( konteksti : konteksti , x : bool , y : bool ) -> Ei mitään :
"""
Toiminto, joka suorittaa testejä
"""
-kontekstitulkkillamme . määrittää ( 'x' , x )
konteksti . assign ( 'y' , y )
lauseke = OrLaus ( # (tosi ja x) tai (y ja (ei x))
AndExp ( VakioLaus ( True ), VariableExp ( 'x' )),
AndExp ( MuuttujaLaus ( 'y' ) , NotExp ( VariableExp ( 'x' )))
)
print ( lauseke . arvioida ( konteksti ))
if __name__ == '__main__' :
print ( 'OUTPUT:' )
konteksti = Konteksti ()
execute_test ( konteksti , tosi , epätosi )
execute_test ( konteksti , epätosi , tosi )
execute_test ( konteksti , epätosi , epätosi )
'''
TULOS:
tosi
tosi
Väärin
'''
PHP lähdekoodi
<?php
/**
* Esimerkki tulkin kuviosta koostumuksella
*/
abstrakti luokka Lauseke {
yksityinen staattinen $_count = 0 ;
yksityinen $_avain = null ;
julkinen abstrakti funktio tulkita ( InterpreterContext $context );
public function getKey () {
if ( ! isset ( $this -> _key ) ) {
self :: $_count ++ ;
$this -> _key = itse :: $_count ;
}
return $this -> _key ;
}
}
class LiteralExpression laajentaa lausekkeen {
yksityinen $_arvo = null ;
julkinen funktio __konstrukti ( $arvo ) {
$this -> _value = $arvo ;
}
public function interpret ( InterpreterContext $context ) {
$context -> korvaa ( $this , $this -> _value );
}
}
class VariableExpression laajentaa lausekkeen {
yksityinen $_nimi = null ;
yksityinen $_val = null ;
julkinen funktio __konstrukti ( $nimi , $val = null ) {
$this -> _name = $nimi ;
$this -> _val = $val ;
}
julkinen funktio tulkita ( InterpreterContext $konteksti ) {
if ( ! is_null ( $this -> _val ) )
$context -> korvaa ( $this , $this -> _val );
}
julkinen funktio setValue ( $arvo ) {
$this -> _val = $arvo ;
}
public function getKey () {
return $this -> _name ;
}
}
abstrakti luokka OperatorExpression laajentaa lausekkeen {
suojattu $leftoperand = null ;
suojattu $rightoperand = null ;
public function __construct ( Lauseke $vasenoperand , Lauseke $oikeaoperand ) {
$this -> leftoperand = $vasenoperand ;
$this -> rightoperand = $rightoperand ;
}
julkinen funktio tulkita ( InterpreterContext $context ) {
$this -> leftoperand -> interpret ( $context );
$this -> rightoperand -> tulkita ( $context );
$resultleft = $konteksti -> haku ( $this -> leftoperand );
$resultright = $konteksti -> haku ( $this -> rightoperand );
$this -> doInterpret ( $context , $resultleft , $resultright );
}
suojattu abstrakti funktio doInterpret ( InterpreterContext $context , $resultleft , $resultright );
}
class EqualsExpression laajentaa OperatorExpression {
suojattu toiminto doInterpret ( InterpreterContext $context , $resultleft , $resultright ) {
$konteksti -> korvaa ( $this , $resultleft == $resultright );
}
}
class BooleanOrExpression laajentaa OperatorExpression {
suojattu toiminto doInterpret ( InterpreterContext $context , $resultleft , $resultright ) {
$konteksti -> korvaa ( $this , $resultleft || $resultright );
}
}
class BooleanAndExpression laajentaa OperatorExpression {
suojattu toiminto doInterpret ( InterpreterContext $context , $resultleft , $resultright ) {
$context -> korvaa ( $this , $resultleft && $resultright );
}
}
class InterpreterContext {
yksityinen $_expressionstore = array ();
julkinen funktio korvaa ( Lauseke $exp , $arvo ) {
$this -> _expressionstore [ $exp -> getKey ()] = $arvo ;
}
julkinen funktiohaku ( Lauseke $exp ) { return $this -> _expressionstore [ $exp -> getKey ( )]; }
}
$konteksti = uusi tulkkikonteksti ();
$syöte = new VariableExpression ( 'input' );
$lauseke = uusi BooleanOrExpression (
uusi EqualsExpression ( $syöttö , uusi LiteralExpression ( "neljä" ) ),
uusi EqualsExpression ( $syöte , uusi LiteralExpression ( "4" ) )
);
foreach ( array ( "neljä" , "4" , "52" ) as $value ) {
$input -> setValue ( $arvo );
tulosta " { $arvo } :<br>" ;
$lausunto -> tulkita ( $konteksti );
tulosta $context -> lookup ( $lauseke )
? "Meets<br><br>"
: "Ei vastaa<br><br>" ;
}
?>
Katso myös