프로그래밍/자바 디자인패턴

디자인패턴 Interpreter 패턴

가카리 2012. 8. 27. 20:42
반응형

Interpreter 패턴

 

이번 패턴은 도스나 리눅스에서 명령어를 치게되는데

 

shell> ls –a

 

이런식으로 치죠?

 

이때 shell>은 무시하고 ls는 명령어고 –a는 옵션이란 것을 인식하게됩니다.

 

이런식으로 여러 클래스를 만들어서 shell>만 인식하는 클래스 ls만 인식하는 클래스 –a만 인식하는 클래스는 만들어서 각자 할 수 있는 것만 처리하게 해봅시다.

 

 

 

 

여기서 나오는 명령어는 자동차를 움직입니다.

 

program go end 이런식입니다.

 

program은 위의 shell>과 같이 그냥 시작을 알리는 것이고 go는 명령어 end는 끝을 알립니다.

 

만약

 

program repeat 4 go right end end

 

repeat 4 4번 반복하라는 뜻이고 어떤 것이면 go right 4번 반복하라는 뜻입니다.

 

그리고 첫번째 end repeat end이고 두번째는 program end입니다. c언어의 중괄호로 묶는거랑 같습니다.

 

이름

해설

Node

구문 트리의 노트가 되는 클래스

ProgramNode

program 에 대응하는 클래스

CommandListNode

command list에 대응하는 클래스

CommandNode

command에 대응하는 클래스

RepeatCommandNode

repeat command에 대응하는 클래스

PrimitiveCommandNode

primitive command에 대응하는 클래스

Context

구문해석을 위한 전후 관계를 나타내는 클래스

ParseException

구문해석 중의 예외 클래스

Main

동작 테스트용 클래스

 

 

 

 

 

다음을 실행하기 위해서는

 

 

 

 

위와같은 program.txt파일을 만들어야 합니다.

 

Node 클래스

 

package exam.kch;

 

public abstract class Node {

 

           public abstract void parse(Context context)throws ParseException;

           //parse메소드의 의미는 program go right 같은 것을 읽는다는 의미입니다.

 

}

 

ProgramNode 클래스

 

package exam.kch;

 

 

public class ProgramNode extends Node{

 

           private Node commandListNode;

 

           @Override

           public void parse(Context context) throws ParseException {

                     // TODO Auto-generated method stub

                    

                     context.skipToken("program");//program이란 명령어는 skip .

                     commandListNode = new CommandListNode();//그 다음 명령어리스트 처리를 위해서 인스턴스를 만들고

                     commandListNode.parse(context);//context 같이 넘겨줌.

 

           }

 

           public String toString(){

                     return "[program " + commandListNode + "]";//여기서 commandListNode.toString()이 불려짐

                                                                                                                                                                                    //이 메소드는 CommandListNode에 있음

           }

 

}

 

 

CommandListNode 클래스

 

package exam.kch;

 

import java.util.ArrayList;

 

public class CommandListNode extends Node{

 

           private ArrayList list = new ArrayList();

          

           @Override

           public void parse(Context context) throws ParseException {

                     // TODO Auto-generated method stub

                    

                     while(true){

                                if(context.currentToken() == null){

                                         

                                          throw new ParseException("Missing 'end'");

                               

                                }else if(context.currentToken().equals("end")){//여기가 끝나는점 여기때문에 무한루프가 안걸림.

                               

                                          context.skipToken("end");

                                          break;

                               

                                }else{

                                         

                                          //commandNodeList 다음에 commandNode로 넘어야됨

                                          //명령어리스트 다음에는 명령어이므로.

                                          Node commandNode = new CommandNode();

                                          commandNode.parse(context);

                                          list.add(commandNode);

                               

                                }

                     }

           }

          

           public String toString(){

                     return list.toString();

           }

 

 

}

 

 

CommandNode 클래스

 

package exam.kch;

 

public class CommandNode extends Node{

           private Node node;

          

           public void parse(Context context) throws ParseException{

                    

                     //여기서는 명령어가 repeat 커맨드인지 아닌지를 구분함.

                     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 클래스

 

package exam.kch;

 

 

public class RepeatCommandNode extends Node{

 

           private int number;

           private Node commandListNode;

          

           @Override

           public void parse(Context context) throws ParseException {

                     // TODO Auto-generated method stub

                    

                     //repeat 명령어의 경우는 repeat 3 이런식으로 쓰므로 3을 추출해야됨

                     context.skipToken("repeat");

                     number = context.currentNumber();//3추출

                     context.nextToken();//다음것을 가리킴

                     commandListNode = new CommandListNode();//CommandListNode로 넘겨줌

                     commandListNode.parse(context);

           }

          

           public String toString(){

                    

                     return "[repeat " + number + " " + commandListNode +"]";

           }

 

}

 

 

PrimitiveCommandNode 클래스

 

package exam.kch;

 

public class PrimitiveCommandNode extends Node{

                    

                     private String name;

                     public void parse(Context context) throws ParseException{

                               

                                //repeat 명령어가 아니면 여기를 오게됨.

                                name = context.currentToken();//현재 명령어 받아오고

                                context.skipToken(name);//다음 명령어 가리킴

                               

                                //go, right, left 아니면 예외발생

                                if(!name.equals("go")&& !name.equals("right") && !name.equals("left")){

                                          throw new ParseException(name + " is undefined");

                                }

                     }

                    

                     public String toString(){

                                return name;

                     }

          

}

 

 

Context 클래스

 

package exam.kch;

 

import java.util.StringTokenizer;

 

public class Context {

 

          

           //StringTokenizer 클래스는 공백, , 줄바꿈, 캐리지 리턴, 폼피트로 구분을 해서 토큰(단어)으로 나눠줌.

           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) throws ParseException{

                    

                     //없다면 예외발생

                     if(!token.equals(currentToken)){

                                throw new ParseException("Warning : " + token + " is expected, but " + currentToken + " is found.");

                     }

                    

                     //다음것을 가리킴

                     nextToken();

                    

           }

          

           //현재 숫자를 가져옴.

           public int currentNumber() throws ParseException{

                    

                     int number = 0;

                    

                     try{

                    

                                number = Integer.parseInt(currentToken);

                    

                     }catch(NumberFormatException e){

                                          throw new ParseException("Warning: " + e);

                               

                     }

                    

                     return number;

                    

           }

          

}

 

 

ParseException 클래스

 

 

package exam.kch;

 

public class ParseException extends Exception{

 

           public ParseException(String msg){

                     super(msg);

           }

          

}

 

 

Main 클래스

 

package exam.kch;

 

import java.io.BufferedReader;

import java.io.FileReader;

 

public class Main {

 

           public static void main(String[] args){

                     try{

                                BufferedReader reader = new BufferedReader(new FileReader("program.txt"));

                                String text;

                               

                                while((text = reader.readLine()) != null){

                                          System.out.println("text = \"" + text + "\"");

                                          Node node = new ProgramNode();//program이란 단어를 스킵하기 위해서 처음에 program 인스턴스를 만듬

                                          node.parse(new Context(text));//이때 skip하거나 next 명령어를 처리하는 것은 Context클래스이므로 인스턴스를 넘겨줌

                                                                                                                                                     //여기서 text 한줄 읽은 명령어임

                                          System.out.println("node = " + node);

                                }

                     }catch (Exception e){

                                e.printStackTrace();

                     }

           }

          

}

 

 

 

 

간단하게 명령어를 입력하면 각 클래스가 자기가 맡은 부분만 처리하고 다른 부분은 다른 클래스로 넘기게 됩니다. 또한 새로운 명령어가 나오면 새로운 클래스를 생성하기만 하면됩니다.

 

반응형

'프로그래밍 > 자바 디자인패턴' 카테고리의 다른 글

디자인패턴 Command 패턴  (1) 2012.08.18
디자인패턴 Proxy 패턴  (0) 2012.08.16
디자인패턴 Flyweight 패턴  (0) 2012.08.15
디자인패턴 State 패턴  (0) 2012.08.14
디자인 패턴 Memento 패턴  (0) 2012.08.13
디자인패턴 Observer 패턴  (0) 2012.08.10
디자인패턴 Mediator 패턴  (0) 2012.08.09
디자인패턴 Facade 패턴  (0) 2012.08.06