<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    細心!用心!耐心!

    吾非文人,乃市井一俗人也,讀百卷書,跨江河千里,故申城一游; 一兩滴辛酸,三四年學業(yè),五六點粗墨,七八筆買賣,九十道人情。

    BlogJava 聯(lián)系 聚合 管理
      1 Posts :: 196 Stories :: 10 Comments :: 0 Trackbacks
    對於一個具有層次節(jié)點關(guān)係的問題來說,如果您要剖析每一個節(jié)點,您可以使用Interpreter模式,直譯器模式有些類似演算法中的個別擊破方式,對每一個父節(jié)點我們剖析出其子節(jié)點組合,然而交給子節(jié)點剖析物件繼續(xù)剖析,直到剖析至終端節(jié)點為止。

    舉個例子來說明好了,先說明的是,這個例子是改寫自 Design Patterns於Java語言之實習應(yīng)用 第23章的範例,我將之更簡化了,以讓大家將焦點能集中在如何使用Interpreter模式,以及如何實用。

    假設(shè)您要實作一個Interpreter,這個Interpreter可以直譯您文字檔中的程式,並依您自訂的程式文法來執(zhí)行程式,幾個簡單的程式如下:
    PROGRAM
        PRINT dog SPACE
        PRINT is SPACE
        PRINT an SPACE
        PRINT animai
    END
     
    您的這式程個會印出"dog is an animal"的文字,再來一個例子是:
    PROGRAM
        REPEAT 2
            LINEBREAK
            PRINT dog
            BREAK
        END
    END
     

    這個程式要印出:
    ------------------------------
     dog
    ------------------------------
     dog

    您也可以任意的組合程式,例如:
    PROGRAM
        PRINT begin
        BREAK
        REPEAT 3
            REPEAT 2
                PRINT dog SPACE
                PRINT is SPACE
                PRINT a SPACE
                PRINT animal
                BREAK
            END
        END
    END
     

    這個程式中的幾個關(guān)鍵字是PROGRAM、PRINT、SPACE、BREAK、LINEBREAK、REPEAT、END, PROGRAM是表示程式開始,以END作結(jié),PRINT可以印出一個無空白的字串,SPACE印出一個空白,BREAK是換行,而LINEBREAK是畫一個直線並換行,REPEAT是迴圈指令,可以指定迴圈次數(shù),以END作結(jié)。

    觀察程式,可以制定出以下的文法,如下:
    <program> ::= PROGRAM <command list>
    <command list> ::= <command>* END
    <command> ::= <repeat command> | <primitive command>
    <repeat command> ::= REPEAT <number> <command list>
    <primitive command> ::= PRINT <string>
                             | BREAK | SPACE | LINEBREAK
     

    程式文法制定需要對程式進行語句分析與定義,在這邊並不討論這個課題,在程式中,command節(jié)點由primitive或repeat兩個節(jié)點任意組合,一個command list節(jié)點則是零個以上的command節(jié)點組合而成,其中repeat還可以組合command list節(jié)點,這是組合模式的應(yīng)用,可以在程式中組合巢狀迴圈。

    在直譯程式時,以讀到PROGRAM作為開始節(jié)點,接下來我們剖析程式為command list 節(jié)點,並將它們丟給專門剖析command list的物件繼續(xù)剖析,這個物件將之分析,看是不是有repeat command或primitive command節(jié)點,如果有就再往下交由專屬物件進行剖析,如此層層剝開,並由專屬物件負責剖析工作。

    Interpreter模式的基本觀念就如上所示,先來看看如何以程式實現(xiàn)剖析的過程,下面這個程式會剖析您的程式,並將程式加上對應(yīng)的括號來將同一個區(qū)塊組合起來,以表示它完成剖析之後的結(jié)果:
    • INode.java
    public interface INode { 
    public void parse(Context context);
    }

    • ProgramNode.java
    // <program> ::= PROGRAM <command list> 
    public class ProgramNode implements INode {
    private INode commandListNode;
    public void parse(Context context) {
    context.skipToken("PROGRAM");
    commandListNode = new CommandListNode();
    commandListNode.parse(context);
    }

    public String toString() {
    return "[PROGRAM " + commandListNode + "]";
    }
    }

    • CommandListNode.java
    import java.util.Vector; 

    // <command list> ::= <command>* END
    public class CommandListNode implements INode {
    private Vector list = new Vector();

    public void parse(Context context) {
    while (true) {
    if (context.currentToken() == null) {
    System.err.println("Missing 'END'");
    break;
    } else if (
    context.currentToken().equals("END")) {
    context.skipToken("END");
    break;
    } else {
    INode commandNode = new CommandNode();
    commandNode.parse(context);
    list.add(commandNode);
    }
    }
    }

    public String toString() {
    return "" + list;
    }
    }

    • CommandNode.java
    // <command> ::= <repeat command> | <primitive command> 
    public class CommandNode implements INode {
    private INode node;

    public void parse(Context context) {
    if (context.currentToken().equals("REPEAT")) {
    node = new RepeatCommandNode();
    node.parse(context);
    } else {
    node = new PrimitiveCommandNode();
    node.parse(context);
    }
    }

    public String toString() {
    return node.toString();
    }
    }

    • RepeatCommandNode.java
    public class RepeatCommandNode implements INode { 
    private int number;
    private INode commandListNode;

    public void parse(Context context) {
    context.skipToken("REPEAT");
    number = context.currentNumber();
    context.nextToken();
    commandListNode = new CommandListNode();
    commandListNode.parse(context);
    }

    public String toString() {
    return "[REPEAT " + number + " "
    + commandListNode + "]";
    }
    }

    • PrimitiveCommandNode.java
    // <primitive command> ::= PRINT <string> 
    // | SPACE | BREAK | LINEBREAK
    public class PrimitiveCommandNode implements INode {
    private String name;
    private String text;

    public void parse(Context context) {
    name = context.currentToken();
    context.skipToken(name);
    if (!name.equals("PRINT") && !name.equals("BREAK")
    && !name.equals("LINEBREAK")
    && !name.equals("SPACE")) {
    System.err.println("Undefined Command");
    }

    if (name.equals("PRINT")) {
    text = context.currentToken();
    name += text;
    context.nextToken();
    }
    }

    public String toString() {
    return name;
    }
    }

    • Context.java
    import java.util.*; 

    public class Context {
    private StringTokenizer tokenizer;
    private String currentToken;

    public Context(String text) {
    tokenizer = new StringTokenizer(text);
    nextToken();
    }

    public String nextToken() {
    if (tokenizer.hasMoreTokens()) {
    currentToken = tokenizer.nextToken();
    } else {
    currentToken = null;
    }
    return currentToken;
    }

    public String currentToken() {
    return currentToken;
    }

    public void skipToken(String token) {
    if (!token.equals(currentToken)) {
    System.err.println("Warning: " + token +
    " is expected, but " +
    currentToken + " is found.");
    }
    nextToken();
    }

    public int currentNumber() {
    int number = 0;
    try {
    number = Integer.parseInt(currentToken);
    } catch (NumberFormatException e) {
    System.err.println("Warning: " + e);
    }
    return number;
    }
    }

    • Main.java
    import java.util.*; 
    import java.io.*;

    public class Main {
    public static void main(String[] args) {
    try {
    BufferedReader reader = new
    BufferedReader(new FileReader(args[0]));
    String text;
    while ((text = reader.readLine()) != null) {
    System.out.println("text = \"" +
    text + "\"");
    INode node = new ProgramNode();
    node.parse(new Context(text));
    System.out.println("node = " + node);
    }
    }
    catch (ArrayIndexOutOfBoundsException e) {
    System.err.println(
    "Usage: java Main yourprogram.txt");
    }
    catch (Exception e) {
    e.printStackTrace();
    }
    }
    }

    假設(shè)您的程式是這樣寫的:
    • program.txt
    PROGRAM PRINT xxx END
    PROGRAM REPEAT 4 PRINT xxx END END
    PROGRAM REPEAT 4 PRINT xxx PRINT "yyy" END END

    則執(zhí)行Intrepreter程式之後會是:
     $ java Main program.txt
     text = "PROGRAM PRINT xxx END"
     node = [PROGRAM [PRINTxxx]]

     text = "PROGRAM REPEAT 4 PRINT xxx END END"
     node = [PROGRAM [[REPEAT 4 [PRINTxxx]]]]

     text = "PROGRAM REPEAT 4 PRINT xxx PRINT "yyy" END END"
     node = [PROGRAM [[REPEAT 4 [PRINTxxx, PRINT"yyy"]]]]

    這個範例程式基本上已經(jīng)顯示了直譯器模式的工作原理,如何讓程式直譯之後能夠工作,這待會再示範,先來看一下Intrepreter模式的 UML 類別結(jié)構(gòu)圖:
    Intrepreter

    TerminalExpression就像我們的primitive command,再剖析下去已經(jīng)沒有子節(jié)點了,而NonterminalExpression就像是repeat command,注意到其中也使用了組合模式,就如之前所說的,組合模式讓可以遞迴的組合句子為更複雜的語句。

    您已經(jīng)會剖析句子了,接下來要如何讓這個直譯器真正工作,雖然程式中使用toString()來表示每一個節(jié)點的剖析結(jié)果,但事實上,這個程式也已經(jīng)說明了如何讓剖析的結(jié)果真正運作了,既然已經(jīng)記錄好剖析之後的語句順序了,只要由上而下追蹤剖析結(jié)果,就一定可以執(zhí)行到 primitive command,且順序符合自訂的程式原始碼的需求,這只要將toString()改為execute(),並作一些轉(zhuǎn)發(fā)與重複執(zhí)行的修改就可以了,直接來看程式會比較容易理解:
    • INode.java
    public interface INode {
    public void parse(Context context);
    public void execute();
    }

    • ProgramNode.java
    // <program> ::= PROGRAM <command list>
    public class ProgramNode implements INode {
    private INode commandListNode;

    public void parse(Context context) {
    context.skipToken("PROGRAM");
    commandListNode = new CommandListNode();
    commandListNode.parse(context);
    }

    public void execute() {
    commandListNode.execute();
    }

    public String toString() {
    return "[PROGRAM " + commandListNode + "]";
    }
    }

    • CommandListNode.java
    import java.util.*;    

    // <command list> ::= <command>* END
    public class CommandListNode implements INode {
    private Vector list = new Vector();
    private INode commandNode;

    public void parse(Context context) {
    while (true) {
    if (context.currentToken() == null) {
    System.err.println("Missing 'END'");
    break;
    } else if(context.currentToken().equals("END")) {
    context.skipToken("END");
    break;
    } else {
    commandNode = new CommandNode();
    commandNode.parse(context);
    list.add(commandNode);
    }
    }
    }

    public void execute() {
    Iterator it = list.iterator();
    while (it.hasNext()) {
    ((CommandNode)it.next()).execute();
    }
    }

    public String toString() {
    return "" + list;
    }
    }

    • CommandNode.java
    // <command> ::= <repeat command> | <primitive command>
    public class CommandNode implements INode {
    private INode node;

    public void parse(Context context) {
    if (context.currentToken().equals("REPEAT")) {
    node = new RepeatCommandNode();
    node.parse(context);
    } else {
    node = new PrimitiveCommandNode();
    node.parse(context);
    }
    }

    public void execute() {
    node.execute();
    }

    public String toString() {
    return node.toString();
    }
    }

    • PrimitiveCommandNode.java
    // <primitive command> ::= PRINT <string> 
    // | SPACE | BREAK | LINEBREAK
    public class PrimitiveCommandNode implements INode {
    private String name;
    private String text;

    public void parse(Context context) {
    name = context.currentToken();
    context.skipToken(name);
    if (!name.equals("PRINT") && !name.equals("BREAK")
    && !name.equals("LINEBREAK")
    && !name.equals("SPACE")) {
    System.err.println("Undefined Command");
    }

    if (name.equals("PRINT")) {
    text = context.currentToken();
    context.nextToken();
    }
    }

    public void execute() {
    if(name.equals("PRINT"))
    System.out.print(text);
    else if(name.equals("SPACE"))
    System.out.print(" ");
    else if(name.equals("BREAK"))
    System.out.println();
    else if(name.equals("LINEBREAK"))
    System.out.println(
    "\n------------------------------");
    }

    public String toString() {
    return name;
    }
    }

    • RepeatCommandNode.java
    public class RepeatCommandNode implements INode {
    private int number;
    private INode commandListNode;

    public void parse(Context context) {
    context.skipToken("REPEAT");
    number = context.currentNumber();
    context.nextToken();
    commandListNode = new CommandListNode();
    commandListNode.parse(context);
    }

    public void execute() {
    for(int i = 0; i < number; i++)
    commandListNode.execute();
    }

    public String toString() {
    return "[REPEAT " + number + " " +
    commandListNode + "]";
    }
    }

    • Context.java
    import java.util.*;

    public class Context {
    private StringTokenizer tokenizer;
    private String currentToken;

    public Context(String text) {
    tokenizer = new StringTokenizer(text);
    nextToken();
    }

    public String nextToken() {
    if (tokenizer.hasMoreTokens()) {
    currentToken = tokenizer.nextToken();
    } else {
    currentToken = null;
    }
    return currentToken;
    }

    public String currentToken() {
    return currentToken;
    }

    public void skipToken(String token) {
    if (!token.equals(currentToken)) {
    System.err.println("Warning: " + token +
    " is expected, but " +
    currentToken + " is found.");
    }
    nextToken();
    }

    public int currentNumber() {
    int number = 0;
    try {
    number = Integer.parseInt(currentToken);
    } catch (NumberFormatException e) {
    System.err.println("Warning: " + e);
    }
    return number;
    }
    }

    • Main.java
    import java.util.*;
    import java.io.*;

    public class Main {
    public static void main(String[] args) {
    try {
    BufferedReader reader = new BufferedReader(
    new FileReader(args[0]));
    String text;
    while ((text = reader.readLine()) != null) {
    System.out.println("text = \"" + text
    + "\"");
    INode node = new ProgramNode();
    node.parse(new Context(text));
    node.execute();
    }
    }
    catch (ArrayIndexOutOfBoundsException e) {
    System.err.println(
    "Useage: java Main yourprogram.txt");
    }
    catch (Exception e) {
    e.printStackTrace();
    }
    }
    }

    假設(shè)您的直譯程式稿是這麼撰寫的:
    • program.txt
    PROGRAM REPEAT 4 LINEBREAK PRINT justin SPACE PRINT momor LINEBREAK END END

    則程式執(zhí)行的結(jié)果就是:
      $ java Main program.txt
     text = "PROGRAM REPEAT 4 LINEBREAK PRINT justin SPACE
             PRINT momor LINEBREAK END END"
     ------------------------------
     justin momor
     ------------------------------

     ------------------------------
     justin momor
     ------------------------------

     ------------------------------
     justin momor
     ------------------------------

     ------------------------------
     justin momor
     ------------------------------ 

    Design Patterns於Java語言之實習應(yīng)用 第23章的範例中,可以讓您依指令稿直譯,畫出任何的圖案,讓範例結(jié)合了工廠(Factory)模式、外觀(Facade)模式等等,在這邊建議您看看那個範例,看看不同的設(shè)計模式之間如何組合且相互合作。
    posted on 2007-04-17 10:47 張金鵬 閱讀(324) 評論(0)  編輯  收藏 所屬分類: Behavioral 模式
    主站蜘蛛池模板: 亚洲综合婷婷久久| 久久久亚洲欧洲日产国码农村| 成年大片免费视频| 国产福利在线免费| 国产成人免费A在线视频| 亚洲欧洲久久久精品| 亚洲国产一区二区三区青草影视| 亚洲成人网在线观看| 国产精品亚洲综合网站| 中文无码成人免费视频在线观看| 亚洲视频在线观看免费视频| 国产免费人视频在线观看免费| 国产成人无码综合亚洲日韩| 亚洲一区二区免费视频| 亚美影视免费在线观看| 四虎最新永久免费视频| 亚洲人成无码网WWW| 亚洲婷婷第一狠人综合精品| A国产一区二区免费入口| 成人黄动漫画免费网站视频 | 国产男女猛烈无遮挡免费视频网站 | a级毛片免费播放| 67194成是人免费无码| 亚洲AV无码国产丝袜在线观看| 亚洲精品第一国产综合亚AV| 国产偷伦视频免费观看| 国产一卡二卡≡卡四卡免费乱码| 免费福利资源站在线视频| 日本免费一区二区在线观看| 亚洲中文字幕无码久久| 57pao国产成视频免费播放| 亚洲 欧洲 自拍 另类 校园| 国产香蕉免费精品视频| 国产亚洲精品国产| 性生大片视频免费观看一级| 日本xxwwxxww在线视频免费| 亚洲婷婷第一狠人综合精品| 波多野结衣免费视频观看| 亚洲国产成人久久精品大牛影视| 亚洲av高清在线观看一区二区 | 99久久婷婷免费国产综合精品|