Design Pattern Learning 22 (Java Implementation)-Interpreter Mode

Design Pattern Learning 22 (Java Implementation)-Interpreter Mode

Write in front

  • Take notes on learning design patterns
  • Improve flexible use of design patterns

Learning address

www.bilibili.com/video/BV1G4...

www.bilibili.com/video/BV1Np...

Reference article

c.biancheng.net/view/1317.h...

Project source code

gitee.com/zhuang-kang...

24, interpreter mode

Design a software to perform addition and subtraction calculations. Our first idea is to use tool classes to provide corresponding addition and subtraction tools.

//Used to add two integers public static int add ( int a, int b) { return a + b; } //Used to add two integers public static int add ( int a, int b, int c) { return a + b + c; } //For adding n integers public static int add (Integer ... arr) { int sum = 0 ; for (Integer i: arr) { sum += i; } return sum; } Copy code

The above form is relatively simple and limited. If the form changes a lot, this does not meet the requirements, because addition and subtraction operations, the two operators and values can have infinite combinations. For example, 1+2+3+4+5, 1+2+3-4 and so on.

Obviously, there is now a need for a translation recognition machine that can parse the legal operation sequence composed of numbers and +-symbols. If you treat both operators and numbers as nodes, you can read and analyze operations node by node. This is the thinking of interpreter mode.

24.1 Definition and characteristics of interpreter mode

Definition of Interpreter mode: **Define a language for the analysis object, define the grammatical representation of the language, and then design a parser to interpret the sentences in the language. **In other words, use the compiled language to analyze the examples in the application. This mode implements an interface for grammatical expression processing, which interprets a specific context.

The concept of syntax and sentence mentioned here is the same as the description in the principle of compilation. "Grammar" refers to the grammatical rules of the language, and "sentence" is an element in the language set. For example, there are many sentences in Chinese, and "I am a Chinese" is one of the sentences. A syntax tree can be used to intuitively describe the sentences in the language.

The interpreter mode is a behavior-like mode, and its main advantages are as follows.

  1. Good scalability. Since classes are used to represent the syntax rules of the language in the interpreter mode, the syntax can be changed or extended through mechanisms such as inheritance.
  2. easy to accomplish. Each expression node class in the syntax tree is similar, so it is easier to implement its syntax.

The main disadvantages of the interpreter mode are as follows.

  1. The execution efficiency is low. The interpreter mode usually uses a large number of loops and recursive calls. When the sentence to be interpreted is more complicated, its running speed is very slow, and the debugging process of the code is also more troublesome.
  2. Will cause class expansion. Each rule in the interpreter mode needs to define at least one class. When there are many grammatical rules included, the number of classes will increase sharply, making the system difficult to manage and maintain.
  3. There are relatively few applicable scenarios. In software development, there are very few application examples that need to define language syntax, so this mode is rarely used.

24.2 The structure and implementation of the interpreter pattern

24.2.1 The structure of the interpreter pattern

  • Abstract Expression (Abstract Expression) role: defines the interface of the interpreter, agrees on the interpretation operation of the interpreter, and mainly includes the interpretation method interpret().
  • The role of Terminal Expression: It is a subclass of abstract expressions used to implement operations related to terminals in the syntax. Each terminal in the syntax has a specific terminal expression corresponding to it.
  • The role of Nonterminal Expression: It is also a subclass of abstract expressions, used to implement operations related to nonterminal symbols in the syntax. Each rule in the syntax corresponds to a nonterminal expression.
  • Context role: usually contains data or common functions required by each interpreter, and is generally used to transfer data shared by all interpreters, and subsequent interpreters can obtain these values from here.
  • Client: The main task is to convert the sentence or expression that needs to be analyzed into an abstract syntax tree described by the interpreter object, and then call the interpretation method of the interpreter. Of course, the interpretation method of the interpreter can also be accessed indirectly through the environment role. .

24.2.2 Code Implementation

Relationship class diagram

AbstractExpression

package com.zhuang.interpreter; /** * @Classname AbstractExpression * @Description abstract role * @Date 2021/3/31 9:45 * @Created by dell */ public abstract class AbstractExpression { public abstract int interpret (Context context) ; } Copy code

Value

package com.zhuang.interpreter; /** * @Classname Value * @Description terminator expression role * @Date 2021/3/31 9:48 * @Created by dell */ public class Value extends AbstractExpression { private int value; public Value ( int value) { this .value = value; } @Override public int interpret (Context context) { return value; } @Override public String toString () { return new Integer(value).toString(); } } Copy code

Plus

package com.zhuang.interpreter; /** * @Classname Plus * @Description non-terminal symbol expression role addition expression * @Date 2021/3/31 9:46 * @Created by dell */ public class Plus extends AbstractExpression { private AbstractExpression left; private AbstractExpression right; public Plus (AbstractExpression left, AbstractExpression right) { this .left = left; this .right = right; } @Override public int interpret (Context context) { return left.interpret(context) + right.interpret(context); } @Override public String toString () { return "(" + left.toString() + "+" + right.toString() + ")" ; } } Copy code

Minus

package com.zhuang.interpreter; /** * @Classname Minus * @Description non-terminal symbol expression role subtraction expression * @Date 2021/3/31 9:46 * @Created by dell */ public class Minus extends AbstractExpression { private AbstractExpression left; private AbstractExpression right; public Minus (AbstractExpression left, AbstractExpression right) { this .left = left; this .right = right; } @Override public int interpret (Context context) { return left.interpret(context)-right.interpret(context); } @Override public String toString () { return "(" + left.toString() + "-" + right.toString() + ")" ; } } Copy code

Variable

package com.zhuang.interpreter; /** * @Classname Variable * @Description terminator expression role variable expression * @Date 2021/3/31 9:46 * @Created by dell */ public class Variable extends AbstractExpression { private String name; public Variable (String name) { this .name = name; } @Override public int interpret (Context context) { return context.getValue( this ); } @Override public String toString () { return name; } } Copy code

Context

package com.zhuang.interpreter; import java.util.HashMap; import java.util.Map; /** * @Classname Context * @Description environment class * @Date 2021/3/31 9:46 * @Created by dell */ public class Context { private Map<Variable, Integer> map = new HashMap<Variable, Integer>(); public void assign (Variable var , Integer value) { map.put( var , value); } public int getValue (Variable var ) { Integer value = map.get( var ); return value; } } Copy code

Client

package com.zhuang.interpreter; /** * @Classname Client * @Description Interpretation power mode test class * @Date 2021/3/31 9:46 * @Created by dell */ public class Client { public static void main (String[] args) { Context context = new Context(); Variable a = new Variable( "a" ); Variable b = new Variable( "b" ); Variable c = new Variable( "c" ); Variable d = new Variable( "d" ); Variable e = new Variable( "e" ); context.assign(a, 2 ); context.assign(b, 3 ); context.assign(c, 4 ); context.assign(d, 5 ); context.assign(e, 6 ); AbstractExpression expression = new Minus( new Plus( new Plus( new Plus(a, b), c), d), e); System.out.println(expression + "=" + expression.interpret(context)); } } Copy code

24.3 Interpreter mode usage scenarios

  • When the syntax of the language is relatively simple, and execution efficiency is not a key issue.
  • When the problem recurs and can be expressed in a simple language.
  • When a language needs to be interpreted and executed, and the sentences in the language can be expressed as an abstract syntax tree.

25, state mode

25.1 Definition and characteristics of state mode

The definition of State mode: For stateful objects, complex "judgment logic" is extracted into different state objects, allowing state objects to change their behavior when their internal state changes.

State mode is an object behavioral mode, and its main advantages are as follows.

  1. The structure is clear, and the state mode localizes the behaviors related to a specific state into one state, and separates the behaviors of different states to meet the "single responsibility principle".
  2. Display state transitions to reduce interdependence between objects. Introducing different states into independent objects will make state transitions more explicit and reduce the interdependence between objects.
  3. The status class has clear responsibilities, which is conducive to the expansion of the program. It is easy to add new states and transitions by defining new subclasses.

The main disadvantages of state mode are as follows.

  1. The use of state mode will inevitably increase the number of classes and objects in the system.
  2. The structure and implementation of the state mode are relatively complicated, and if used improperly, it will cause confusion in the program structure and code.

25.2

public interface ILift { //4 states of the elevator //door opening state public final static int OPENING_STATE = 1 ; //door closing state public final static int CLOSING_STATE = 2 ; //running state public final static int RUNNING_STATE = 3 ; //stop State public final static int STOPPING_STATE = 4 ; //Set the state of the elevator public void setState ( int state) ; //Elevator action public void open () ; public void close () ; public void run () ; public void stop () ; } public class Lift implements ILift { private int state; @Override public void setState ( int state) { this .state = state; } //Perform the closing action @Override public void close () { switch ( this .state) { case OPENING_STATE: System.out.println(" ");// this.setState(CLOSING_STATE);// break; case CLOSING_STATE: //do nothing// break; case RUNNING_STATE: //do nothing// break; case STOPPING_STATE: //do nothing// break; } } // @Override public void open() { switch (this.state) { case OPENING_STATE:// //do nothing break; case CLOSING_STATE://: System.out.println(" "); this.setState(OPENING_STATE); break; case RUNNING_STATE: //do nothing break; case STOPPING_STATE: System.out.println(" ");// this.setState(OPENING_STATE); break; } } // @Override public void run() { switch (this.state) { case OPENING_STATE:// //do nothing break; case CLOSING_STATE:// System.out.println(" "); this.setState(RUNNING_STATE);// break; case RUNNING_STATE: //do nothing break; case STOPPING_STATE: System.out.println(" "); this.setState(RUNNING_STATE); break; } } // @Override public void stop() { switch (this.state) { case OPENING_STATE: //( ) //do nothing break; case CLOSING_STATE:// System.out.println(" "); this.setState(STOPPING_STATE); break; case RUNNING_STATE:// System.out.println(" "); this.setState(STOPPING_STATE); break; case STOPPING_STATE: //do nothing break; } } } public class Client { public static void main(String[] args) { Lift lift = new Lift(); lift.setState(ILift.STOPPING_STATE);// lift.open();// lift.close();// lift.run();// lift.stop();// } }

  • switch case if else )

25.2.1

  • Context
  • State
  • Concrete State

25.2.2

LiftState

package com.zhuang.state.after; /** * @Classname LiftState * @Description * @Date 2021/3/31 10:50 * @Created by dell */ public abstract class LiftState { // protected Context context; public void setContext(Context context) { this.context = context; } // public abstract void open(); // public abstract void close(); // public abstract void run(); // public abstract void stop(); }

Context

package com.zhuang.state.after; /** * @Classname Context * @Description * @Date 2021/3/31 10:53 * @Created by dell */ public class Context { // // public final static OpeningState OPENNING_STATE = new OpeningState(); // public final static ClosingState CLOSEING_STATE = new ClosingState(); // public final static RunningState RUNNING_STATE = new RunningState(); // public final static StoppingState STOPPING_STATE = new StoppingState(); // private LiftState liftState; public LiftState getLiftState() { return this.liftState; } public void setLiftState(LiftState liftState) { // this.liftState = liftState; // this.liftState.setContext(this); } public void open() { this.liftState.open(); } public void close() { this.liftState.close(); } public void run() { this.liftState.run(); } public void stop() { this.liftState.stop(); } }

OpeningState

package com.zhuang.state.after; /** * @Classname OpeningState * @Description * @Date 2021/3/31 10:51 * @Created by dell */ public class OpeningState extends LiftState { // @Override public void open() { System.out.println(" ..."); } @Override public void close() { // super.context.setLiftState(Context.CLOSEING_STATE); //CloseState ClosingState super.context.getLiftState().close(); } // @Override public void run() { //do nothing } // @Override public void stop() { //do nothing } }

ClosingState

package com.zhuang.state.after; /** * @Classname ClosingState * @Description * @Date 2021/3/31 10:52 * @Created by dell */ public class ClosingState extends LiftState { @Override // public void close() { System.out.println(" ..."); } // @Override public void open() { super.context.setLiftState(Context.OPENNING_STATE); super.context.open(); } // @Override public void run() { super.context.setLiftState(Context.RUNNING_STATE); super.context.run(); } // @Override public void stop() { super.context.setLiftState(Context.STOPPING_STATE); super.context.stop(); } }

RunningState

package com.zhuang.state.after; /** * @Classname RunningState * @Description * @Date 2021/3/31 10:52 * @Created by dell */ public class RunningState extends LiftState { @Override public void open() { // } @Override public void close() { // } @Override public void run() { System.out.println(" ..."); } @Override public void stop() { // super.context.setLiftState(Context.OPENNING_STATE); super.context.stop(); } }

StoppingState

package com.zhuang.state.after; /** * @Classname StoppingState * @Description * @Date 2021/3/31 10:51 * @Created by dell */ public class StoppingState extends LiftState { @Override public void open() { // super.context.setLiftState(Context.OPENNING_STATE); //CloseState ClosingState super.context.getLiftState().open(); } @Override public void close() { // super.context.setLiftState(Context.CLOSEING_STATE); //CloseState ClosingState super.context.getLiftState().close(); } @Override public void run() { // super.context.setLiftState(Context.RUNNING_STATE); //CloseState ClosingState super.context.getLiftState().run(); } @Override public void stop() { System.out.println(" ..."); } }

Client

package com.zhuang.state.after; /** * @Classname Client * @Description * @Date 2021/3/31 10:53 * @Created by dell */ public class Client { public static void main(String[] args) { // System.out.println(" -->"); Context context1 = new Context(); context1.setLiftState(new OpeningState()); context1.open(); context1.close(); context1.run(); context1.stop(); System.out.println("========================="); // System.out.println(" -->"); Context context2 = new Context(); context2.setLiftState(new ClosingState()); context2.open(); context2.close(); context2.run(); context2.stop(); System.out.println("========================="); // System.out.println(" -->"); Context context3 = new Context(); context3.setLiftState(new RunningState()); context3.open(); context3.close(); context3.run(); context3.stop(); System.out.println("========================="); // System.out.println(" -->"); Context context4 = new Context(); context4.setLiftState(new StoppingState()); context4.open(); context4.close(); context4.run(); context4.stop(); } }

25.3