# 設計模式 第十章 備忘錄模式、直譯器模式、狀態模式
前言
備忘錄模式、直譯器模式、狀態模式
一、備忘錄模式
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);
}
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());
}
}
--結果
狀態標記為開始
狀態為開始
狀態標記為結束
狀態為結束