第17章 行為型模式—直譯器模式
1. 直譯器模式(Interpreter Pattern)的定義
(1)定義
給定一個語言,定義它的文法的一種表示,並定義一個直譯器,這個直譯器使用該表示來解釋語言中的句子。
①文法:即語法規則。在直譯器模式中每一個語法都將對應一個直譯器物件,用來處理相應的語法規則。它對於擴充套件、改變文法以及增加新的文法規則都很方便。
②直譯器模式描述瞭如何為簡單的語言定義一個文法,如何在該語言中表示一個句子,以及如何解釋這些句子。
③在直譯器模式中可以通過一種稱之為抽象語法樹(Abstract Syntax Tree, AST)的圖形方式來直觀地表示語言的構成,每一棵抽象語法樹對應一個語言例項
(2)直譯器模式的結構和說明
①AbstractExpression:定義直譯器的介面,約定直譯器的解釋操作。其中的Interpret介面,正如其名字那樣,它是專門用來解釋該直譯器所要實現的功能。(如加法直譯器中的Interpret介面就是完成兩個運算元的相加功能)。
②TerminalExpression:終結符直譯器,用來實現語法規則中和終結符相關的操作,不再包含其他的直譯器,如果用組合模式來構建抽象語法樹的話,就相當於組合模式中的葉子物件,可以有多種終結符直譯器。
③NonterminalExpression:非終結符直譯器,用來實現語法規則中非終結符相關的操作,通常一個直譯器對應一個語法規則,可以包含其他直譯器,如果用組合模式構建抽象語法樹的話,就相當於組合模式中的組合物件
④Context:上下文,通常包含各個直譯器需要的資料或是公共的功能。這個Context在直譯器模式中起著非常重要的作用。一般用來傳遞被所有直譯器共享的資料,後面的直譯器可以從這裡獲取這些值。
⑤Client:客戶端,指的是使用直譯器的客戶端,通常在這裡將按照語言的語法做的表示式轉換成使用直譯器物件描述的抽象語法樹,然後呼叫解釋操作。
【程式設計實驗】四則運算(注意終結符直譯器與非終結直譯器的劃分)
//行為型模式:直譯器模式 //場景:四則運算 #include <iostream> #include <string> #include <map> #include <stack> #include <typeinfo> using namespace std; //*******************************************抽象表示式類*********************************** class Expression { public: //解析公式和數值,其中var中的key是公式中的引數,value值是具體的數字 //如a = 100; b = 20; c = 40 virtual int interpreter(map<string, int>& var) = 0; virtual ~Expression(){}; }; //變數解析器(終結符表示式) class VarExpression : public Expression { string key; public: VarExpression(string key) { this->key = key; } //從map中取出變數的值 int interpreter(map<string, int>& var) { return var[key]; } ~VarExpression() { cout << "~VarExpression()" << endl; } }; //**********抽象運算子號解析器*********************** //抽象運算子號解析器 class SymbolExpression : public Expression { protected: Expression* left; Expression* right; public: SymbolExpression(Expression* left, Expression* right) { this -> left = left; this -> right = right; } Expression* getLeft() { return left; } Expression* getRight() { return right; } }; //加法解析器 class AddExpression : public SymbolExpression { public: AddExpression(Expression* left, Expression* right): SymbolExpression(left,right) { } //把左右兩個表示式運算的結果加起來 int interpreter(map<string, int>& var) { return left->interpreter(var) + right ->interpreter(var); } ~AddExpression() { cout << "~AddExpression()" << endl; } }; //減法解析器 class SubExpression : public SymbolExpression { public: SubExpression(Expression* left, Expression* right): SymbolExpression(left,right) { } //把左右兩個表示式運算的結果相減 int interpreter(map<string, int>& var) { return left->interpreter(var) - right ->interpreter(var); } ~SubExpression() { cout << "~SubExpression()" << endl; } }; //*********************************解析器封裝類*************************************** //解析器封裝類,這個類是根據迪米特法則進行封裝,目的是讓Client只與直接朋友打交道,相當於Facade class Calculator { private: Expression* expression; public: //建構函式傳參,並解析表示式,構建語法樹 Calculator(string expStr) { expression = NULL; //棧,用來暫存中間結果 stack<Expression*> stkExp; Expression* left = NULL; Expression* right = NULL; /*從左到向分析表示式(如:a+b-c),最終的語法樹如下: * - * / \ * + c * / \ * a b */ for(unsigned int i = 0; i< expStr.length(); i++) { switch(expStr[i]) { case '+': //加法 //1.先從棧中取出左運算元 left = stkExp.top(); stkExp.pop(); //2.從表示式中取出+號後面的右運算元,並生成終結符解析物件 right = new VarExpression(expStr.substr(++i,1)); //3.將左右運算元相加,並把結果放入棧中 stkExp.push(new AddExpression(left, right)); break; case '-': //1.先從棧中取出左運算元 left = stkExp.top(); stkExp.pop(); //2.從表示式中取出+號後面的右運算元,並生成終結符解析物件 right = new VarExpression(expStr.substr(++i,1)); //3.將左右運算元相減,並把結果放入棧中 stkExp.push(new SubExpression(left, right)); break; default: //如果是變數(終結符):如a+b+c中的a\b\c, //則直接生成對應的變數解析器物件 stkExp.push(new VarExpression(expStr.substr(i,1))); } } //棧中儲存的就是最終語法樹的根結點(本例為SuuExpression物件) if(!stkExp.empty()) { expression = stkExp.top(); stkExp.pop(); } } void deltree(Expression* expression) { SymbolExpression* branch = dynamic_cast<SymbolExpression*>(expression); //葉子結點 if (branch == NULL) { delete expression; } else //分支結點 { //左子樹 deltree(branch->getLeft()); //右子樹 deltree(branch->getRight()); //結點 delete expression; } } ~Calculator() { deltree(expression); expression = NULL; } //開始運算 int run(map<string, int>& var) { return (expression == NULL) ? 0 : expression->interpreter(var); } }; int main() { string expStr = "a+b-c"; //為簡化處理,這裡必須是合法的表示式 map<string, int> var; //相當於Interpreter模式中的Context var["a"] = 100; var["b"] = 20; var["c"] = 40; Calculator cal(expStr); cout <<"運算結果為:" << expStr << " = " << cal.run(var) << endl; return 0; } /* 運算結果為:a+b-c = 80 ~VarExpression() ~VarExpression() ~AddExpression() ~VarExpression() ~SubExpression() */
2. 思考直譯器模式
(1)直譯器模式的本質:分離實現,解釋執行。通過一個直譯器物件處理一個語法規則的方式,把複雜的功能分離開,然後選擇需要被執行的功能,並把這些功能組合成需要解釋執行的抽象語法樹,再按照抽象語法樹來解釋執行,實現相應的功能。從本質上看,直譯器模式的思路仍然是分離、封裝和簡化,這與很多其他模式是一樣的。
(2)誰來構建抽象語法樹——解析器
解析器的工作主要就是用來構建抽象語法樹的,這個角色會客戶端轉來的語言,負責按語法規則,生成一個個直譯器,並將這些直譯器組合成一顆抽象語法樹。注意,解析器的工作主要是構造語法樹,而直譯器的工作是解釋這顆語法樹。
(3)誰來負責解釋操作 ——直譯器(Interpreter)
只要定義好了抽象語法樹,肯定是直譯器來負責解釋執行,而選擇直譯器的工作,在構建抽象語法樹的時候就完成了,一般由根結點的直譯器開始解釋,然後遞迴地呼叫其他直譯器。
【程式設計實驗】中文數字轉阿拉伯數字(注意Context的應用)
//行為型模式:直譯器模式
//場景:中文數字轉阿拉伯數字
/*
1、使用Interpreter模式來將中文數字轉換為數學數字的好處是可以應對中文數字的變化,
雖然可以用一很好的演算法將中文轉化為數字,直譯器的擴充套件效能比較好,如果出現億、兆的情況,
可以寫出兩個類(YiExpression、ZhaoExpression)來繼承Expression類,而其他地方的程式碼都不變化。
2、思路:用單位用分解出不同的直譯器.其中個位、十位、百位和千位是終結符直譯器,萬位是非結終符
直譯器,因為萬以上的單位可以形成如果九百零一萬之類的數字,需要進一進拆分成由結終符
構成的直譯器來完成任務。
3、轉化:將中文數字串由低位向高位方向不斷轉化
*/
#include <iostream>
#include <string>
#include <map>
#include <stack>
#include <list>
using namespace std;
//字串上下文資訊:儲存沒有處理的字串資訊
class Context
{
private:
string statement;
int data;
public:
Context(string statement)
{
this ->statement = statement;
data = 0;
}
string& getStatement()
{
return statement;
}
void setStatement(string statement)
{
this -> statement = statement;
}
int getData()
{
return data;
}
void setData(int data)
{
this -> data = data;
}
};
//抽象類:直譯器
class Expression
{
protected:
//資料字典:儲存中文數字一到九
static map<string, int> table;
//輔助函式,用來判判斷src字串是否以tail串結尾
bool stringEndsWith(const string& src, const string& tail)
{
if(src.size() < tail.size())
return false;
string tmp = src.substr(src.size() - tail.size(), tail.size());
return (0==tmp.compare(0,tail.size(),tail));
}
public:
//虛方法:中文數字到數字的轉換
virtual void interpret(Context& context)
{
if(context.getStatement().length() == 0)
return;
map<string, int>::iterator iter = table.begin();
while (iter != table.end())
{
string& statement = context.getStatement();
string tail = iter->first + getPostfix();
//從低位往高位分析(如九千三百零五,從右向左分析)
if(stringEndsWith(statement,tail))
{
context.setData(context.getData() + iter->second * multiplier());
//注意,string是ASCII編碼,每個中文字元的長度為2
context.setStatement(statement.substr(0, statement.length()-2 - getPostfix().length()));
}
if(stringEndsWith(statement,"零"))
{
//”零“則直接跳過
context.setStatement(statement.substr(0, statement.length()-2));
}
++iter;
}
}
//表示式的字尾是以什麼表示的(十、百...)
virtual string getPostfix() = 0;
//表示式的數量級
virtual int multiplier() = 0;
virtual ~Expression(){};
};
//對映表,儲存中文數字與羅馬數字的對映
static map<string, int>::value_type init_table[] =
{
map<string, int>::value_type("一",1),
map<string, int>::value_type("二",2),
map<string, int>::value_type("三",3),
map<string, int>::value_type("四",4),
map<string, int>::value_type("五",5),
map<string, int>::value_type("六",6),
map<string, int>::value_type("七",7),
map<string, int>::value_type("八",8),
map<string, int>::value_type("九",9)
};
map<string,int> Expression::table(init_table,init_table + 9);
//個位數直譯器(終結符表示式)
class GeExpression : public Expression
{
public:
string getPostfix()
{
return "";
}
int multiplier()
{
return 1;
}
};
//十位數直譯器(終結符表示式)
class ShiExpression : public Expression
{
public:
string getPostfix()
{
return "十";
}
int multiplier()
{
return 10;
}
};
//百位數直譯器(終結符表示式)
class BaiExpression : public Expression
{
public:
string getPostfix()
{
return "百";
}
int multiplier()
{
return 100;
}
};
//千位數直譯器(終結符表示式)
class QianExpression : public Expression
{
public:
string getPostfix()
{
return "千";
}
int multiplier()
{
return 1000;
}
};
//萬位數直譯器(非終結符表示式)
class WanExpression : public Expression
{
public:
string getPostfix()
{
return "萬";
}
int multiplier()
{
return 10000;
}
void interpret(Context& context)
{
if(context.getStatement().length() == 0)
return ;
if (stringEndsWith(context.getStatement(),getPostfix()))
{
list<Expression*> exps;
exps.clear();
exps.push_back(new GeExpression());
exps.push_back(new ShiExpression());
exps.push_back(new BaiExpression());
exps.push_back(new QianExpression());
int temp = context.getData();
string& sm = context.getStatement();
context.setData(0);
//string類中每個中文長度為2.
context.setStatement(sm.substr(0, sm.length()-2));
list<Expression*>::iterator iter = exps.begin();
while (iter != exps.end())
{
(*iter)->interpret(context);
++iter;
}
context.setData(temp + multiplier()* context.getData());
iter = exps.begin();
while (iter != exps.end())
{
delete (*iter);
++iter;
}
exps.clear();
}
}
};
//轉換器
class Convertor
{
private:
Context context;
string chineseNum;
int result;
list<Expression*> exps;
void reset()
{
context.setStatement(chineseNum);
context.setData(0);
list<Expression*>::iterator iter = exps.begin();
while (iter != exps.end())
{
delete (*iter);
++iter;
}
exps.clear();
}
public:
Convertor(const string chineseNum):context(chineseNum)
{
this ->chineseNum = chineseNum;
result = 0;
}
void convert()
{
reset();
exps.push_back(new GeExpression());
exps.push_back(new ShiExpression());
exps.push_back(new BaiExpression());
exps.push_back(new QianExpression());
exps.push_back(new WanExpression());
list<Expression*>::iterator iter = exps.begin();
while (iter != exps.end())
{
(*iter)->interpret(context);
++iter;
}
result = context.getData();
}
int getRoman()
{
return result;
}
void setChineseNum(const string& chineseNum)
{
this ->chineseNum = chineseNum;
}
~Convertor()
{
reset();
}
};
int main()
{
string chineseNum = "四百九十六萬二千三百一十五";
Convertor conv(chineseNum);
conv.convert();
cout << chineseNum << " -> " << conv.getRoman() << endl;
chineseNum = "九千零五萬六千零七十二";
conv.setChineseNum(chineseNum);
conv.convert();
cout << chineseNum << " -> " << conv.getRoman() << endl;
return 0;
}
/*輸出結果:
四百九十六萬二千三百一十五 -> 4962315
九千零五萬六千零七十二 -> 90056072
*/
3. 直譯器模式的優缺點
(1)優點
①易於實現文法:在直譯器模式中,一條語法規則用一個直譯器物件來解釋執行。對於直譯器的實現來講,功能就變得比較簡單,只需要考慮這一條語法規則的實現就可以了,其他的都不用管。
②易於擴充套件新的語法。由於直譯器採用類來描述語法規則,因此可以通過繼承等機制建立相應的直譯器物件,在建立抽象語法樹的時候使用這個新的直譯器物件就可以了。
(2)缺點
①執行效率較低。由於在直譯器模式中使用了大量的迴圈和遞迴呼叫,因此在解釋較為複雜的句子時其速度很慢,而且程式碼的除錯過程也比較麻煩。
②對於複雜文法難以維護。在直譯器模式中,每一條規則至少需要定義一個類,因此如果一個語言包含太多文法規則,類的個數將會急劇增加,導致系統難以管理和維護,此時可以考慮使用語法分析程式等方式來取代直譯器模式。
4. 直譯器模式的應用場景
(1)當一個語言需要解釋執行,並可以將該語言中的句子表示為一個抽象語法樹的時候,可以考慮使用直譯器模式(如XML文件解釋、正則表示式等領域)
(2)一些重複出現的問題可以用一種簡單的語言來進行表達。
(3)一個語言的文法較為簡單.
(4)當執行效率不是關鍵和主要關心的問題時可考慮直譯器模式(注:高效的直譯器通常不是通過直接解釋抽象語法樹來實現的,而是需要將它們轉換成其他形式,使用直譯器模式的執行效率並不高。)
【程式設計實驗】機器人控制程式
//行為型模式:直譯器模式
//場景:開發一套機器人控制程式
/*說明:
機器人控制程式中包含一些簡單的英文控制指令,每一個指令對應一個表示式(expression),
該表示式可以是簡單表示式也可以是複合表示式,每一個簡單表示式由移動方向(direction),
移動方式(action)和移動距離(distance)三部分組成,其中移動方向包括上(up)、下(down)、
左(left)、右(right);移動方式包括移動(move)和快速移動(run);移動距離為一個正整數。
兩個表示式之間可以通過與(and)連線,形成複合(composite)表示式。
使用者通過對圖形化的設定介面進行操作可以建立一個機器人控制指令,機器人在收到指令
後將按照指令的設定進行移動,例如輸入控制指令:up move 5,則“向上移動5個單位”;輸入控
制指令:down run 10 and left move 20,則“向下快速移動10個單位再向左移動20個單位”。
*/
/*文法規則
expression ::= direction action distance | composite //表示式
composite ::= expression 'and' expression //複合表示式
direction ::= 'up' | 'down' | 'left' | 'right' //移動方向
action ::= 'move' | 'run' //移動方式
distance ::= an integer //移動距離
上述語言一共定義了五條文法規則,對應五個語言單位,這些語言單位可以分為兩類,
終結符(也稱為終結符表示式):例如direction、action和distance,它們是語言的最小組成單位,不能再進行拆分;
非終結符(也稱為非終結符表示式),例如expression和composite,它們都是一個完整的句子,包含一系列終結符或非終結符。
*/
//本例項對機器人控制指令的輸出結果進行模擬,將英文指令翻譯為中文指令,實際情況是呼叫不同的控制程式進行機器人的控制,
//包括對移動方向、方式和距離的控制等
#include <iostream>
#include <string>
#include <stack>
#include <vector>
#include <typeinfo>
using namespace std;
//////////////////////////////////////////////////////////////////////////
// 字串分割
//
// -------------------------------------------------------------------------
// 函式 : Split
// 功能 : 分割STL標準字串
// 返回值 : void
// 引數 : Container<std::basic_string<CharT> >& v 存放分割結果
// 引數 : const std::basic_string<CharT>& s 待分割字串
// 引數 : const std::basic_string<CharT>& c 分割字串
// -------------------------------------------------------------------------
template<typename CharT, template<typename S, typename Q = std::allocator<S> > class Container>
void Split(Container<std::basic_string<CharT> >& v, const std::basic_string<CharT>& s, const std::basic_string<CharT>& c);
template<template<typename S, typename Q = std::allocator<S> > class Container>
void Split(Container<std::basic_string<char> >& v, const std::basic_string<char>& s, const std::basic_string<char>& c)
{
if (0 == c.length())
return;
std::basic_string<char>::size_type pos1 = 0;
std::basic_string<char>::size_type pos2 = 0;
pos1 = 0;
pos2 = s.find(c);
while (std::basic_string<char>::npos != pos2)
{
v.push_back(s.substr(pos1, pos2 - pos1));
pos1 = pos2 + c.size();
pos2 = s.find(c, pos1);
}
if (pos1 != s.length())
{
v.push_back(s.substr(pos1));
}
}
//抽象類:直譯器
class AbstractExpression
{
public:
virtual string interpret() = 0;
virtual ~AbstractExpression(){}
};
//And直譯器:非終結符表示式
class AndExpression : public AbstractExpression
{
private:
AbstractExpression* left ; //And的左表示式
AbstractExpression* right; //And的右表示式
public:
AndExpression(AbstractExpression* left,
AbstractExpression* right)
{
this->left = left;
this->right = right;
}
//And表示式解釋操作
string interpret()
{
return left->interpret() + "再" + right->interpret();
}
AbstractExpression* getLeft()
{
return left;
}
AbstractExpression* getRight()
{
return right;
}
};
//簡單句子直譯器:非終結符表示式
//如:up move 5,表示“向上移動5個單位
class SentenceExpression : public AbstractExpression
{
private:
AbstractExpression* direction;
AbstractExpression* action;
AbstractExpression* distance;
public:
SentenceExpression(AbstractExpression* direction,
AbstractExpression* action,
AbstractExpression* distance)
{
this->direction = direction;
this->action = action;
this->distance = distance;
}
//解釋操作
string interpret()
{
return direction->interpret() + action->interpret() + distance->interpret();
}
AbstractExpression* getDirection()
{
return direction;
}
AbstractExpression* getAction()
{
return action;
}
AbstractExpression* getDistance()
{
return distance;
}
};
//方向直譯器:終結符表示式
class DirectionExpression : public AbstractExpression
{
private:
string direction;
public:
DirectionExpression(string direction)
{
this->direction = direction;
}
//方向表示式的解釋操作
string interpret()
{
if(direction =="up")
{
return "向上";
}
else if(direction == "down")
{
return "向下";
}
else if(direction == "left")
{
return "向左";
}
else if(direction == "right")
{
return "向右";
}
else
{
return "無效指令";
}
}
};
//動作直譯器:(終結符表示式)
class ActionExpression : public AbstractExpression
{
private:
string action;
public:
ActionExpression(string action)
{
this->action = action;
}
//動作移動表示式的解釋操作
string interpret()
{
if(action == "move")
{
return "移動";
}
else if(action == "run")
{
return "快速移動";
}
else
{
return "無效指令";
}
}
};
//距離直譯器:(終結符表示式)
class DistanceExpression : public AbstractExpression
{
private:
string distance;
public:
DistanceExpression(string distance)
{
this->distance = distance;
}
string interpret()
{
return distance;
}
};
//指令處理類:工具類
class InstructionHandler
{
private:
AbstractExpression* mExp;
void delTree(AbstractExpression* exp) //刪除最終的生成的抽象樹
{
//葉子結果
bool bLeaf = typeid(*exp) ==typeid(DirectionExpression) ||
typeid(*exp) ==typeid(ActionExpression) ||
typeid(*exp) ==typeid(DistanceExpression);
AndExpression* andExp = dynamic_cast<AndExpression*>(exp);
SentenceExpression* sentenceExp = dynamic_cast<SentenceExpression*>(exp);
if(bLeaf)
{
delete exp;
}
else if (andExp != NULL) //And表示式
{
AbstractExpression* left = andExp->getLeft();
AbstractExpression* right = andExp->getRight();
delTree(left);
delTree(right);
delete andExp;
}
else if(sentenceExp != NULL) //簡單句子表示式
{
AbstractExpression* dir = sentenceExp->getDirection();
AbstractExpression* act = sentenceExp->getAction();
AbstractExpression* dis = sentenceExp->getDistance();
delTree(dir);
delTree(act);
delTree(dis);
delete sentenceExp;
}
else
{
}
}
public:
InstructionHandler():mExp(NULL){}
void handle(string instruction){
AbstractExpression* left = NULL;
AbstractExpression* right = NULL;
AbstractExpression* direction = NULL;
AbstractExpression* action = NULL;
AbstractExpression* distance = NULL;
if (mExp!=NULL)
{
delTree(mExp);
mExp = NULL;
}
//宣告一個棧物件用於儲存抽象語法樹
stack<AbstractExpression*> stkExp;
vector<string> words;
Split(words, instruction, " "); //以空格分隔指令字串
for(unsigned int i=0; i<words.size(); i++){
//本例項採用棧的方式來處理指令,如果遇到and則將其後的三個單詞連成一個簡單句子(Sentence)
//作為"and"的右表示式,而將棧頂彈出的表示式作為"and"的左表示式,最後將新的And表示式壓入棧中
string dir("");
string act("");
string dis("");
if(words[i] =="and"){
//從彈出棧頂作為and的左表示式
left = stkExp.top();
stkExp.pop();
dir = words[++i];
direction = new DirectionExpression(dir);
act = words[++i];
action = new ActionExpression(act);
dis = words[++i];
distance = new DistanceExpression(dis);
//組成一個簡單表示式作為And的右表示式
right = new SentenceExpression(direction, action, distance);
//生成And表示式,並壓入棧中
stkExp.push(new AndExpression(left, right));
}
//如果不是and表示式,就從頭開始進行解釋,將前3個單詞作為Sentence
//的三個運算元,生成簡單表示式解析器後壓入棧中
else{
dir = words[i];
direction = new DirectionExpression(dir);
act = words[++i];
action = new ActionExpression(act);
dis = words[++i];
distance = new DistanceExpression(dis);
//組成一個簡單表示式作為And的右表示式
stkExp.push(new SentenceExpression(direction, action, distance));
}
}
if(!stkExp.empty()){
mExp = stkExp.top();
stkExp.pop();
}
else
mExp = NULL;
}
string output(){
return mExp==NULL ? "": mExp->interpret();
}
};
int main()
{
string instruction = "up move 5 and down run 10 and left move 5";
InstructionHandler handler;
handler.handle(instruction);
cout <<"輸入指令: " <<instruction <<endl;
cout <<"移動結果:" << handler.output() << endl;
instruction = "right run 20 and down move 10 and left run 40 and up run 10";
handler.handle(instruction);
cout <<"輸入指令: " <<instruction <<endl;
cout <<"移動結果:" << handler.output() << endl;
return 0;
}
/*輸出結果:
輸入指令: up move 5 and down run 10 and left move 5
移動結果:向上移動5再向下快速移動10再向左移動5
輸入指令: right run 20 and down move 10 and left run 40 and up run 10
移動結果:向右快速移動20再向下移動10再向左快速移動40再向上快速移動10
*/
5. 相關模式
(1)直譯器和組合模式
這兩種可以組合使用,一般非終結符直譯器相當於組合模式中的組合物件,終結符直譯器相當於葉子物件。
(2)直譯器模式和迭代器模式
由於直譯器模式通常使用組合模式來實現,因此在遍歷整個物件結構時,可以使用迭代器模式。
(3)直譯器模式和享元模式
在使用直譯器模式的時候,可能會造成多個細粒度物件,如各式各樣的終結符直譯器,而這些終結符直譯器對不同的表示式來說是一樣的,是可以共用的,因此可以引入享元模式來共享這些物件。
(4)直譯器模式和訪問者模式
在直譯器模式中,語法規則和直譯器物件是有對應關係的。語法規則的變動意味著功能的變化。自然會導致使用不同的直譯器物件;而且一個語法規由可以被不同的直譯器解釋執行。因此在構建抽象語法樹的時候,如果每個節點所對應的直譯器物件是固定的,這意味著該節點對應的功能是固定的,那麼就不得不根據需要來構建不同的抽象語法樹。
為了讓構建的抽象語法樹較為通用,那就要求直譯器的功能不要那麼固定,要能很方便地改變直譯器的功能,這個時候就變成了如何能夠很方便地更改樹形結構中節點物件的功能了,訪問者模式可以很好的實現這個功能。