Dr. Yan Hongs Buch „JAVA and Patterns“ beginnt mit einer Beschreibung des Interpreter-Musters:
Dolmetschermuster ist ein Verhaltensmuster für Klassen. Bei einer gegebenen Sprache definiert das Interpretermuster eine Darstellung ihrer Grammatik und stellt einen Interpreter bereit. Mit diesem Dolmetscher können Kunden Sätze in dieser Sprache dolmetschen.
Die Struktur des Interpretermodus
Nehmen wir als Beispiel ein schematisches System, um die Struktur des Interpretermodus zu diskutieren. Das Systemstrukturdiagramm sieht wie folgt aus:
Die im Muster beteiligten Rollen sind wie folgt:
(1) Rolle des abstrakten Ausdrucks (Ausdruck): Deklarieren Sie eine abstrakte Schnittstelle, die alle konkreten Ausdrucksrollen implementieren müssen. Bei dieser Schnittstelle handelt es sich hauptsächlich um eine interpret()-Methode, die als Interpretationsoperation bezeichnet wird.
(2) Terminalausdrucksrolle: Implementiert die für die abstrakte Ausdrucksrolle erforderliche Schnittstelle, hauptsächlich eine interpret()-Methode. Jedem Terminalsymbol in der Grammatik entspricht ein spezifischer Terminalausdruck. Beispielsweise gibt es eine einfache Formel R=R1+R2, in der R1 und R2 Terminalsymbole sind und der entsprechende Interpreter, der R1 und R2 analysiert, ein Terminalausdruck ist.
(3) Rolle des nichtterminalen Ausdrucks: Jede Regel in der Grammatik erfordert im Allgemeinen einen Operator oder ein anderes Schlüsselwort in der Grammatik, z. B. Formeln. In R=R1+R2 ist „+“ ein nichtterminales Symbol , und der Interpreter, der „+“ analysiert, ist ein nicht-terminaler Symbolausdruck.
(4) Kontextrolle: Die Aufgabe dieser Rolle besteht im Allgemeinen darin, die spezifischen Werte zu speichern, die jedem Terminalsymbol in der Grammatik entsprechen. Beispiel: R = R1 + R2, wir weisen R1 den Wert 100 und den Wert zu 200 bis R2. Diese Informationen müssen in der Umgebungsrolle gespeichert werden. In vielen Fällen reicht es aus, wenn wir Map als Umgebungsrolle verwenden.
Um die Implementierung des Interpretermodus zu veranschaulichen, finden Sie hier die einfachste Grammatik und die entsprechende Implementierung des Interpretermodus, mit der die Operation und Auswertung boolescher Ausdrücke in der Java-Sprache simuliert werden soll.
Terminalsymbole in dieser Sprache sind boolesche Variablen, also die Konstanten true und false. Nichtterminale Ausdrücke umfassen boolesche Ausdrücke wie Operatoren und, oder und nicht. Diese einfache Grammatik lautet wie folgt:
Kopieren Sie den Codecode wie folgt:
Ausdruck ::= Konstante |. Oder |
Und ::= Ausdruck 'AND' Ausdruck
Oder ::= Ausdruck 'OR' Ausdruck
Nicht ::= 'NOT'-Ausdruck
Variable ::= beliebiger Bezeichner
Konstante ::= 'true' |. 'false'
Das Strukturdiagramm des Interpretermodus lautet wie folgt:
Quellcode
abstrakte Ausdrucksrolle
Kopieren Sie den Codecode wie folgt:
öffentlicher abstrakter Klassenausdruck {
/**
* Abhängig von der Umgebung interpretiert diese Methode jeden gegebenen Ausdruck
*/
public abstract boolean interpret(Context ctx);
/**
* Prüfen Sie, ob zwei Ausdrücke strukturell gleich sind
*/
öffentlicher abstrakter boolescher Wert equal(Object obj);
/**
* Gibt den Hash-Code des Ausdrucks zurück
*/
öffentliche Zusammenfassung int hashCode();
/**
* Konvertieren Sie den Ausdruck in einen String
*/
öffentlicher abstrakter String toString();
}
Ein Constant-Objekt stellt eine boolesche Konstante dar
Kopieren Sie den Codecode wie folgt:
öffentliche Klassenkonstante erweitert Ausdruck{
privater boolescher Wert;
öffentliche Konstante (boolescher Wert){
this.value = value;
}
@Override
öffentlicher boolescher Wert gleicht(Objekt obj) {
if(obj != null && obj Instanz der Konstante){
return this.value == ((Constant)obj).value;
}
return false;
}
@Override
public int hashCode() {
return this.toString().hashCode();
}
@Override
public boolean interpret(Context ctx) {
Rückgabewert;
}
@Override
öffentlicher String toString() {
return new Boolean(value).toString();
}
}
Ein Variable-Objekt stellt eine benannte Variable dar. Der Code lautet wie folgt:
öffentliche Klassenvariable erweitert Ausdruck {
privater String-Name;
öffentliche Variable(String-Name){
this.name = Name;
}
@Override
öffentlicher boolescher Wert gleicht(Objekt obj) {
if(obj != null && obj Instanz der Variablen)
{
return this.name.equals(
((Variable)obj).name);
}
return false;
}
@Override
public int hashCode() {
return this.toString().hashCode();
}
@Override
öffentlicher String toString() {
Rückgabename;
}
@Override
public boolean interpret(Context ctx) {
return ctx.lookup(this);
}
}
Die And-Klasse stellt die logische „AND“-Operation dar, die die Operation darstellt, bei der aus zwei booleschen Ausdrücken durch die logische „AND“-Operation ein neuer boolescher Ausdruck erstellt wird.
Kopieren Sie den Codecode wie folgt:
öffentliche Klasse und erweitert Ausdruck {
privater Ausdruck links, rechts;
public And(Ausdruck links, Ausdruck rechts){
this.left = left;
this.right = richtig;
}
@Override
öffentlicher boolescher Wert gleicht(Objekt obj) {
if(obj != null && obj Instanz von And)
{
return left.equals(((And)obj).left) &&
right.equals(((And)obj).right);
}
return false;
}
@Override
public int hashCode() {
return this.toString().hashCode();
}
@Override
public boolean interpret(Context ctx) {
return left.interpret(ctx) && right.interpret(ctx);
}
@Override
öffentlicher String toString() {
return "(" + left.toString() + " AND " + right.toString() + ")";
}
}
Die Or-Klasse stellt die logische „OR“-Operation dar, die die Operation darstellt, aus zwei booleschen Ausdrücken durch die logische „OR“-Operation einen neuen booleschen Ausdruck zu erzeugen.
Kopieren Sie den Codecode wie folgt:
öffentliche Klasse Oder erweitert Ausdruck {
privater Ausdruck links, rechts;
public Or(Ausdruck links, Ausdruck rechts){
this.left = left;
this.right = richtig;
}
@Override
öffentlicher boolescher Wert gleicht(Objekt obj) {
if(obj != null && obj Instanz von Or)
{
return this.left.equals(((Or)obj).left) && this.right.equals(((Or)obj).right);
}
return false;
}
@Override
public int hashCode() {
return this.toString().hashCode();
}
@Override
public boolean interpret(Context ctx) {
return left.interpret(ctx) ||. right.interpret(ctx);
}
@Override
öffentlicher String toString() {
return "(" + left.toString() + " OR " + right.toString() + ")";
}
}
Die Not-Klasse stellt die logische „Nicht“-Operation dar, die die Operation zum Erzeugen eines neuen booleschen Ausdrucks aus einem booleschen Ausdruck durch die logische „Nicht“-Operation darstellt. Kopieren Sie den Code wie folgt:
öffentliche Klasse erweitert den Ausdruck nicht {
privater Ausdruck exp;
public Not(Expression exp){
this.exp = exp;
}
@Override
öffentlicher boolescher Wert gleicht(Objekt obj) {
if(obj != null && obj Instanz von Nicht)
{
return exp.equals(
((Nicht)obj).exp);
}
return false;
}
@Override
public int hashCode() {
return this.toString().hashCode();
}
@Override
public boolean interpret(Context ctx) {
return !exp.interpret(ctx);
}
@Override
öffentlicher String toString() {
return „(Not „ + exp.toString() + „)“;
}
}
Die Context-Klasse definiert eine Zuordnung von Variablen zu booleschen Werten
Kopieren Sie den Codecode wie folgt:
öffentlicher Klassenkontext {
private Map<Variable,Boolean> map = new HashMap<Variable,Boolean>();
public void attachment(Variable var, boolescher Wert){
map.put(var, new Boolean(value));
}
public boolean lookup(Variable var) wirft IllegalArgumentException{
Boolescher Wert = map.get(var);
if(value == null){
throw new IllegalArgumentException();
}
Rückgabewert.booleanValue();
}
}
Client-Klasse
Kopieren Sie den Codecode wie folgt:
öffentliche Klasse Client {
public static void main(String[] args) {
Kontext ctx = neuer Kontext();
Variable x = neue Variable("x");
Variable y = neue Variable("y");
Konstante c = neue Konstante (wahr);
ctx.assign(x, false);
ctx.assign(y, true);
Ausdruck 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));
}
}
Die Laufergebnisse sind wie folgt: