Java-第十八部分-设计模式-解释器模式和状态模式

224 阅读4分钟

设计模式全文

解释器模式

  • 案例,实现四则运算,输入表达式,表达式的字母不能重复
  • 编译原理中,一个算术表达式需要通过词法分析器形成词法单元,这些词法通过语法分析器构建语法分析树。词法分析器和语法分析器都可以是解释器
  • Interpreter Pattern,给定一个语言表达式,定义文法和解释器,解释器用来解释语言中的句子
  • 一些重复出现的问题可以用一种简单的语言来表示,编译器、运算表达式、正则表达式 demo.png
  • 案例类图,将表达式拆成多个部分,用不同的具体解释器去解释 demo2.png
  • 表达式抽象类,Expression
public abstract class Expression {
   //维护变量和数值
   //var-val
   public abstract int interpreter(HashMap<String, Integer> var);
}
  • 变量解释器
public class VarExpression extends Expression {
   private String key; // key=a,key=b,key=c
   public VarExpression(String key) {
      this.key = key;
   }
   @Override
   public int interpreter(HashMap<String, Integer> var) {
      return var.get(this.key);
   }
}
  • 运算符解释器,SymbolExpression
public class SymbolExpression extends Expression {
   protected Expression left;
   protected Expression right;
   public SymbolExpression(Expression left, Expression right) {
      this.left = left;
      this.right = right;
   }
   //通过子类实现
   @Override
   public int interpreter(HashMap<String, Integer> var) {
      return 0;
   }
}
  • 加法解释器,AddExpression
public class AddExpression extends SymbolExpression  {
   public AddExpression(Expression left, Expression right) {
      super(left, right);
   }
   public int interpreter(HashMap<String, Integer> var) {
      //返回左表达式对应的值
      return super.left.interpreter(var) + super.right.interpreter(var);
   }
}
  • 减法解释器,SubExpression
public class SubExpression extends SymbolExpression {
   public SubExpression(Expression left, Expression right) {
      super(left, right);
   }
   public int interpreter(HashMap<String, Integer> var) {
      return super.left.interpreter(var) - super.right.interpreter(var);
   }
}
  • Calculator,计算类,将表达式转换为解释器类,最终通过递归的方式得到答案
public class Calculator {
   private Expression expression;
   public Calculator(String expStr) { // expStr = a+b
      Stack<Expression> stack = new Stack<>();
      char[] charArray = expStr.toCharArray();// [a, +, b]
      Expression left = null;
      Expression right = null;
      for (int i = 0; i < charArray.length; i++) {
         switch (charArray[i]) {
         case '+': //
            //左边是栈顶
            left = stack.pop();
            right = new VarExpression(String.valueOf(charArray[++i]));
            //将和加入
            stack.push(new AddExpression(left, right));
            break;
         case '-': // 
            left = stack.pop();
            right = new VarExpression(String.valueOf(charArray[++i]));
            stack.push(new SubExpression(left, right));
            break;
         default:
            stack.push(new VarExpression(String.valueOf(charArray[i])));
            break;
         }
      }
      //得到最后一个表达式,是递归嵌套的
      this.expression = stack.pop();
   }
   public int run(HashMap<String, Integer> var) {
      return this.expression.interpreter(var);
   }
}
  • 调用
public static void main(String[] args) throws IOException {
   // TODO Auto-generated method stub
   String expStr = getExpStr(); // a+b
   HashMap<String, Integer> var = getValue(expStr);// var {a=10, b=20}
   Calculator calculator = new Calculator(expStr);
   System.out.println("结果" + expStr + "=" + calculator.run(var));
}
public static String getExpStr() throws IOException {
   System.out.print("请输入表达式: ");
   return (new BufferedReader(new InputStreamReader(System.in))).readLine();
}
public static HashMap<String, Integer> getValue(String expStr) throws IOException {
   HashMap<String, Integer> map = new HashMap<>();
   for (char ch : expStr.toCharArray()) {
      if (ch != '+' && ch != '-') {
         if (!map.containsKey(String.valueOf(ch))) {
            System.out.print("请输入" + String.valueOf(ch) + "的值:");
            String in = (new BufferedReader(new InputStreamReader(System.in))).readLine();
            map.put(String.valueOf(ch), Integer.valueOf(in));
         }
      }
   }
   return map;
}

Spring源码

demo.png

  • Expression为接口,有多个实现 image.png
  • 根据不同的parse对象返回不同的Expression对象
  • SpelExpressionParser的父类TemplateAwareExpressionParser
public Expression parseExpression(String expressionString, @Nullable ParserContext context) throws ParseException {
    return context != null && context.isTemplate() ? this.parseTemplate(expressionString, context) : this.doParseExpression(expressionString, context);
}
  • doParseExpression真正由InternalSpelExpressionParser实现,返回SpelExpression对象
  • parseTemplate
private Expression parseTemplate(String expressionString, ParserContext context) throws ParseException {
    if (expressionString.isEmpty()) {
        return new LiteralExpression("");
    } else {
        Expression[] expressions = this.parseExpressions(expressionString, context);
        return (Expression)(expressions.length == 1 ? expressions[0] : new CompositeStringExpression(expressionString, expressions));
    }
}

小结

  • 当一个语言需要解释执行,将语言中的句子表示为一个抽象语法树,拆成几类含义,用对应的解释器解释
  • 可能引起类膨胀,采用递归调用

状态模式

  • 案例,APP抽象活动
  1. 每一次抽象扣除50积分,中奖概率为10%
  2. 奖品数量固定,抽完不能参加
  3. 有四个状态 可以抽奖、不能抽奖、发放奖品、奖品领完
  • State Pattern,用来解决对象在多种状态转换时,需要对外输出不同的行为,状态和行为是一一对应的,当内在状态改变时,允许改变其行为
  • 每一个状态都是一个对象,行为都是独立的 demo.png
  • 案例类图 demo2.png
  • 抽象类,规范了活动中的行为
public abstract class State {
    public abstract void reducePoints();
    //是否抽中奖品
    public abstract boolean raffle();
    public abstract void dispensePrize();
}
  • 不可抽奖状态,可以扣除积分,并设置为抽奖状态
public class NoRaffleState extends State {
    RaffleActivity activity;
    public NoRaffleState(RaffleActivity activity) {
        this.activity = activity;
    }
    //扣除后,设置为可以抽奖的状态
    @Override
    public void reducePoints() {
        System.out.println("扣除50积分");
        activity.setState(activity.getCanRaffleState());
    }
    //当前状态不能抽奖
    @Override
    public boolean raffle() {
        System.out.println("扣了积分才能抽奖");
        return false;
    }
    //不能领奖品
    @Override
    public void dispensePrize() {
        System.out.println("不能领奖品");
    }
}
  • 抽奖状态,开始抽奖
public class CanRaffleState extends State {
    RaffleActivity activity;
    public CanRaffleState(RaffleActivity activity) {
        this.activity = activity;
    }
    @Override
    public void reducePoints() {
        System.out.println("已经扣过积分了");
    }
    @Override
    public boolean raffle() {
        System.out.println("正在抽奖");
        Random r = new Random();
        int num = r.nextInt(10);
        // 10%的概率
        if(num == 0){
            // 抽中了设置为发放奖品
            activity.setState(activity.getDispenseState());
            return true;
        }else{
            System.out.println("没有抽中奖品");
            //改变为不能抽奖
            activity.setState(activity.getNoRafflleState());
            return false;
        }
    }
    @Override
    public void dispensePrize() {
        System.out.println("不能发放奖品");
    }
}
  • 发奖品
public class DispenseState extends State {
    RaffleActivity activity;
    public DispenseState(RaffleActivity activity) {
        this.activity = activity;
    }
    @Override
    public void reducePoints() {
        System.out.println("不能扣积分");
    }
    @Override
    public boolean raffle() {
        System.out.println("不能抽奖");
        return false;
    }
    @Override
    public void dispensePrize() {
        int count = activity.getCount();
        if (count == 1) {
            System.out.println("恭喜中奖");
            //设置为不能抽奖的状态
            activity.setState(activity.getNoRafflleState());
            System.out.println("奖品发完了");
            activity.setState(activity.getFinishState());
            System.out.println("活动结束");
            System.exit(0);
        } else {
            System.out.println("恭喜中奖");
            //设置为不能抽奖的状态
            activity.setState(activity.getNoRafflleState());
        }
    }
}
  • 活动结束
public class FinishState extends State {
    RaffleActivity activity;
    //抽奖活动结束
    public FinishState(RaffleActivity activity) {
        this.activity = activity;
    }
    @Override
    public void reducePoints() {
        System.out.println("不能扣积分");
    }
    @Override
    public boolean raffle() {
        System.out.println("不能抽奖");
        return false;
    }
    @Override
    public void dispensePrize() {
        System.out.println("不能发奖品");
    }
}
  • 活动类,有多个状态
public class RaffleActivity {
    State state = null;
    int count = 0;
    State noRafflleState = new NoRaffleState(this);
    State canRaffleState = new CanRaffleState(this);
    State dispenseState =   new DispenseState(this);
    State finishState = new FinishState(this);
    public RaffleActivity(int count) {
        this.state = getNoRafflleState();
        this.count = count;
    }
    public void redeucePoints(){
        state.reducePoints();
    }
    public void raffle(){
        //先抽奖
        if(state.raffle()){
            //抽中领奖
            state.dispensePrize();
        }
    }
    public int getCount() {
        //获取数量后--
       int curCount = count; 
       count--;
        return curCount;
    }
    //其他的getter和setter
}

借贷平台的应用

  • 借贷平台的订单,有审核、发布、抢单的步骤,每个订单就会有多个状态
  • 状态转移 IMG_CF8214FEDD8D-1.jpeg
  • 类图 demo.png

小结

  • 可读性强,可维护性高,将每个状态的行为封装到类中,符合开闭原则
  • 会产生很多类,每个状态都对应一个类,
  • 适用于一个事件或对象有很多状态,状态之间会相互转换,不同的状态有不同的行为