設計模式 第十章 備忘錄模式、直譯器模式、狀態模式

wpwdm159357發表於2020-12-20

# 設計模式 第十章 備忘錄模式、直譯器模式、狀態模式

前言

	備忘錄模式、直譯器模式、狀態模式

一、備忘錄模式

1.介紹

行為型模式,在不破壞封裝性的前提,捕獲一個物件的狀態,
並在物件之外儲存這個狀態,這樣以後就可將該物件的恢復。

2.程式碼示例

//備忘錄物件
public class Memento {
    private int vit;//攻擊力
    private int drf;//防禦力

    public Memento(int vit, int drf) {
        this.vit = vit;
        this.drf = drf;
    }
    public int getVit() {
        return vit;
    }

    public void setVit(int vit) {
        this.vit = vit;
    }

    public int getDrf() {
        return drf;
    }

    public void setDrf(int drf) {
        this.drf = drf;
    }
}

//封裝物件的一些操作,包括建立狀態和恢復狀態
public class GameRole {
    private int vit;//攻擊力
    private int drf;//防禦力

    public GameRole() {
    }

    public Memento createMemento(){
        return new Memento(vit,drf);
    }

    public void recoverGameRoleFromMemento(Memento memento){
        this.drf = memento.getDrf();
        this.vit = memento.getVit();
    }

    public void dispaly(){
        System.out.println("遊戲角色當前攻擊力:"+ this.vit+" 防禦力:" +this.drf);
    }

    public GameRole(int vit, int drf) {
        this.vit = vit;
        this.drf = drf;
    }

    public int getVit() {
        return vit;
    }

    public void setVit(int vit) {
        this.vit = vit;
    }

    public int getDrf() {
        return drf;
    }

    public void setDrf(int drf) {
        this.drf = drf;
    }
}
//儲存備忘錄物件
public class Caretaker {

    private Memento memento;

    public Caretaker(Memento memento) {
        this.memento = memento;
    }

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}

public class Client {

    public static void main(String[] args) {
        GameRole gameRole = new GameRole();
        gameRole.setDrf(100);
        gameRole.setVit(100);
        System.out.println("和boss大戰之前狀態");
        gameRole.dispaly();

        Caretaker caretaker = new Caretaker(gameRole.createMemento());
        System.out.println("和boss大戰");
        gameRole.setVit(30);
        gameRole.setDrf(30);
        gameRole.dispaly();
        System.out.println("和boss大戰後。恢復狀態");
        gameRole.recoverGameRoleFromMemento(caretaker.getMemento());
        gameRole.dispaly();
    }

}

--結果

和boss大戰之前狀態
遊戲角色當前攻擊力:100 防禦力:100
和boss大戰
遊戲角色當前攻擊力:30 防禦力:30
和boss大戰後。恢復狀態
遊戲角色當前攻擊力:100 防禦力:100



二、直譯器模式

1.介紹

給定一個語言,定義它的文法表示,並定義一個直譯器,這個解釋
器使用該標識來解釋語言中的句子。

2.程式碼示例

//抽象方法
public interface ExpressionParser {
    Expression parseExpression(String var1, ParserContext var2) throws ParseException;
}

//方法的實現
public abstract class TemplateAwareExpressionParser implements ExpressionParser {
    public 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子類實現
    }

 private Expression[] parseExpressions(String expressionString, ParserContext context) throws ParseException {
        List<Expression> expressions = new ArrayList();
        String prefix = context.getExpressionPrefix();
        String suffix = context.getExpressionSuffix();
        int startIdx = 0;

        while(startIdx < expressionString.length()) {
            int prefixIndex = expressionString.indexOf(prefix, startIdx);
            if (prefixIndex >= startIdx) {
                if (prefixIndex > startIdx) {
                    expressions.add(new LiteralExpression(expressionString.substring(startIdx, prefixIndex)));
                }

                int afterPrefixIndex = prefixIndex + prefix.length();
                int suffixIndex = this.skipToCorrectEndSuffix(suffix, expressionString, afterPrefixIndex);
                if (suffixIndex == -1) {
                    throw new ParseException(expressionString, prefixIndex, "No ending suffix '" + suffix + "' for expression starting at character " + prefixIndex + ": " + expressionString.substring(prefixIndex));
                }

                if (suffixIndex == afterPrefixIndex) {
                    throw new ParseException(expressionString, prefixIndex, "No expression defined within delimiter '" + prefix + suffix + "' at character " + prefixIndex);
                }

                String expr = expressionString.substring(prefixIndex + prefix.length(), suffixIndex);
                expr = expr.trim();
                if (expr.isEmpty()) {
                    throw new ParseException(expressionString, prefixIndex, "No expression defined within delimiter '" + prefix + suffix + "' at character " + prefixIndex);
                }

                expressions.add(this.doParseExpression(expr, context));
                startIdx = suffixIndex + suffix.length();
            } else {
                expressions.add(new LiteralExpression(expressionString.substring(startIdx)));
                startIdx = expressionString.length();
            }
        }

        return (Expression[])expressions.toArray(new Expression[0]);
    }

    private boolean isSuffixHere(String expressionString, int pos, String suffix) {
        int suffixPosition = 0;

        for(int i = 0; i < suffix.length() && pos < expressionString.length(); ++i) {
            if (expressionString.charAt(pos++) != suffix.charAt(suffixPosition++)) {
                return false;
            }
        }

        return suffixPosition == suffix.length();
    }
//該方法負責解釋
    private int skipToCorrectEndSuffix(String suffix, String expressionString, int afterPrefixIndex) throws ParseException {
        int pos = afterPrefixIndex;
        int maxlen = expressionString.length();
        int nextSuffix = expressionString.indexOf(suffix, afterPrefixIndex);
        if (nextSuffix == -1) {
            return -1;
        } else {
            ArrayDeque stack;
            for(stack = new ArrayDeque(); pos < maxlen && (!this.isSuffixHere(expressionString, pos, suffix) || !stack.isEmpty()); ++pos) {
                char ch = expressionString.charAt(pos);
                switch(ch) {
                case '"':
                case '\'':
                    int endLiteral = expressionString.indexOf(ch, pos + 1);
                    if (endLiteral == -1) {
                        throw new ParseException(expressionString, pos, "Found non terminating string literal starting at position " + pos);
                    }

                    pos = endLiteral;
                    break;
                case '(':
                case '[':
                case '{':
                    stack.push(new TemplateAwareExpressionParser.Bracket(ch, pos));
                    break;
                case ')':
                case ']':
                case '}':
                    if (stack.isEmpty()) {
                        throw new ParseException(expressionString, pos, "Found closing '" + ch + "' at position " + pos + " without an opening '" + TemplateAwareExpressionParser.Bracket.theOpenBracketFor(ch) + "'");
                    }

                    TemplateAwareExpressionParser.Bracket p = (TemplateAwareExpressionParser.Bracket)stack.pop();
                    if (!p.compatibleWithCloseBracket(ch)) {
                        throw new ParseException(expressionString, pos, "Found closing '" + ch + "' at position " + pos + " but most recent opening is '" + p.bracket + "' at position " + p.pos);
                    }
                }
            }

            if (!stack.isEmpty()) {
                TemplateAwareExpressionParser.Bracket p = (TemplateAwareExpressionParser.Bracket)stack.pop();
                throw new ParseException(expressionString, p.pos, "Missing closing '" + TemplateAwareExpressionParser.Bracket.theCloseBracketFor(p.bracket) + "' for '" + p.bracket + "' at position " + p.pos);
            } else {
                return !this.isSuffixHere(expressionString, pos, suffix) ? -1 : pos;
            }
        }
    }

    protected abstract Expression doParseExpression(String var1, @Nullable ParserContext var2) throws ParseException;

}


public class SpelExpressionParser extends TemplateAwareExpressionParser {
    private final SpelParserConfiguration configuration;

    public SpelExpressionParser() {
        this.configuration = new SpelParserConfiguration();
    }
    protected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context) throws ParseException {
        return (new InternalSpelExpressionParser(this.configuration)).doParseExpression(expressionString, context);
    }
}


三、狀態模式

1. 介紹

主要用來解決物件在多種狀態轉換時,需要對外輸出不同的
行為問題,當一個物件內在狀態改變時,允許改變其行為,
該物件看起來像是改變了其類。

2. 程式碼示例

//更改狀態的介面
public interface State {
   public void doAction(Context context);
}
//具體實現更改狀態介面
public class StartState implements State {
 
   public void doAction(Context context) {
      System.out.println("狀態標記為開始");
      context.setState(this); 
   }
	public void display(){
		System.out.println("狀態為開始");
	}
}

public class StopState implements State {
 
   public void doAction(Context context) {
      System.out.println("狀態標記為結束");
      context.setState(this); 
   }
	public void display(){
		System.out.println("狀態為結束");
	}

}

//儲存狀態物件
public class Context {
   private State state;
 
   public Context(){
      state = null;
   }
 
   public void setState(State state){
      this.state = state;     
   }
 
   public State getState(){
      return state;
   }
   
}
public class Client{
   public static void main(String[] args) {
      Context context = new Context();
 
      StartState startState = new StartState();
      startState.doAction(context);
 
      System.out.println(context.getState().display());
 
      StopState stopState = new StopState();
      stopState.doAction(context);
 
      System.out.println(context.getState().display());
   }
}

--結果
狀態標記為開始
狀態為開始
狀態標記為結束
狀態為結束


相關文章