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 패턴

 

패키지

이름

해설

command

Command

명령을 표현하는 인터페이스

MacroCommand

복수의 명령을 모은 명령을 표현하는 클래스

drawer

DrawCommand

점 그리기 명령을 표현하는 클래스

Drawable

그리기 대상을 표현하는 인터페이스

DrawCanvas

그리기 대상을 구현하는 클래스

Anonymous

Main

동작 테스트용 클래스

 

 

Command 패턴의 핵심은 명령을 시키는 사람과 명령을 구체적인 계획을 가지고 수행하는 사람을 분리시키는 것입니다.

 

 

문서열기나 복사하기나 취소하기 는 셋다 명령입니다. 그리고 명령을 수행시키는 사람은 따로 있습니다.

 

한번 어떻게 분리시켰는지 소스를 보고 실행해봅시다.

 

Command 인터페이스

 

package command;

 

public interface Command {

    public abstract void execute();

}

 

 

MacroCommand 클래스

 

package command;

 

import java.util.Stack;

import java.util.Iterator;

 

public class MacroCommand implements Command {

    // 명령의 집합

    private Stack commands = new Stack();

    // 실행

    public void execute() {

        Iterator it = commands.iterator();

        while (it.hasNext()) {//모든 명령을 실행 여기서 이전에 그렸던 모든 것을 다시 그리게 됨.

            ((Command)it.next()).execute();//execute DrawCommandexecute메소드를 호출할 것임.

        }                              

    }

    // 추가

    public void append(Command cmd) {

        if (cmd != this) {

            commands.push(cmd);//스택을 쌓음

        }

    }

    // 최후의 명령을 삭제

    public void undo() {

        if (!commands.empty()) {

            commands.pop();

        }

    }

    // 전부 삭제

    public void clear() {

        commands.clear();

    }

}

 

 

Drawable 인터페이스

 

package drawer;

 

public interface Drawable {

    public abstract void draw(int x, int y);

}

 

 

DrawCanvas 클래스

 

package drawer;

 

import command.*;

 

import java.util.*;

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

 

/**

 * @author  kch

 */

public class DrawCanvas extends Canvas implements Drawable {

    // 그림 그리는 색

    private Color color = Color.red;

    // 그림 그리는 점의 반경

    private int radius = 6;

    // 이력

    /**

            * @uml.property  name="history"

            * @uml.associationEnd 

            */

    private MacroCommand history;

    // 생성자

    public DrawCanvas(int width, int height, MacroCommand history) {

        setSize(width, height);

        setBackground(Color.white);

        this.history = history;

    }

    // 이력 전체를 다시 그리기  fillOval이 실행되면 이 메소드가 자동적으로 호출됨.

    public void paint(Graphics g) {

        history.execute();//MacroCommandexecute 실행됨

                                                               //즉 모든 명령어가 실행됨.

    }

    // 그림 그리기, x, y좌표에 점을 찍음

    public void draw(int x, int y) {

        Graphics g = getGraphics();

        g.setColor(color);

        g.fillOval(x - radius, y - radius, radius * 2, radius * 2);

    }

}

 

 

DrawCommand 클래스

 

package drawer;

 

import command.Command;

import java.awt.Point;

 

/**

 * @author  kch

 */

public class DrawCommand implements Command {

    // 그림 그리기 대상

    /**

            * @uml.property  name="drawable"

            * @uml.associationEnd 

            */

    protected Drawable drawable;

    // 그림 그리기 위치

    private Point position;

    // 생성자

    public DrawCommand(Drawable drawable, Point position) {

        this.drawable = drawable;

        this.position = position;

    }

    // 실행

    public void execute() {                 

        drawable.draw(position.x, position.y);//x,y 포지션에 그림.

        //drawable 인스턴스는 DrawCanvas이므로 DrawCanvasdraw메소드가 실행됨

    }                                    

 }

 

 

Main 클래스

 

import command.*;

import drawer.*;

 

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

 

/**

 * @author  kch

 */

public class Main extends JFrame implements ActionListener, MouseMotionListener, WindowListener {

    // 그림 그린 이력

    /**

            * @uml.property  name="history"

            * @uml.associationEnd 

            */

    private MacroCommand history = new MacroCommand();

    // 그림 그리는 영역

    /**

            * @uml.property  name="canvas"

            * @uml.associationEnd 

            */

    private DrawCanvas canvas = new DrawCanvas(400, 400, history);

    // 제거 버튼

    private JButton clearButton  = new JButton("clear");

 

    // 생성자

    public Main(String title) {

        super(title);

 

        this.addWindowListener(this);

        canvas.addMouseMotionListener(this);

        clearButton.addActionListener(this);

 

        Box buttonBox = new Box(BoxLayout.X_AXIS);

        buttonBox.add(clearButton);

        Box mainBox = new Box(BoxLayout.Y_AXIS);

        mainBox.add(buttonBox);

        mainBox.add(canvas);

        getContentPane().add(mainBox);

 

        pack();

        show();

    }

 

    // ActionListener

    public void actionPerformed(ActionEvent e) {

        if (e.getSource() == clearButton) {

            history.clear();

            canvas.repaint();

        }

    }

 

    // MouseMotionListener

    public void mouseMoved(MouseEvent e) {

    }

    public void mouseDragged(MouseEvent e) {

        Command cmd = new DrawCommand(canvas, e.getPoint());//초기화할때 canvas 넘겨줌으로써

        //drawable참조변수가 canvas 인스턴스를 가리키게됨.

       

        history.append(cmd);

        cmd.execute();//DrawCommand execute 메소드가 실행됨.

    }

 

    // WindowListener

    public void windowClosing(WindowEvent e) {

        System.exit(0);

    }

    public void windowActivated(WindowEvent e) {}

    public void windowClosed(WindowEvent e) {}

    public void windowDeactivated(WindowEvent e) {}

    public void windowDeiconified(WindowEvent e) {}

    public void windowIconified(WindowEvent e) {}

    public void windowOpened(WindowEvent e) {}

 

    public static void main(String[] args) {

        new Main("Command Pattern Sample");

    }

}

 

결과화면

 

 

 

여기서는 명령은 2가지 종류인데 하나는 지금까지 수행한 명령들을 다 저장하는 것과 다른 하나는 그림판에 그림을 그리는 명령입니다.

 

그리고 명령을 하는 사람은 Main 클래스에서   public void mouseDragged(MouseEvent e) 부분이구요.

 

자 그럼 차근차근 생각해봅시다.

 

처음에 명령이 내려졌습니다. canvas에 빨간 점을 한 개 찍으라는 명령입니다.

 

이 프로그램의 특징은 명령이 내려지면 무조건 그것을 저장하고 그리고 지금까지 저장한 모든 점을 화면에 찍게됩니다.

 

그러면

 

Command cmd = new DrawCommand(canvas, e.getPoint());//초기화할때 canvas 넘겨줌으로써

        //drawable참조변수가 canvas 인스턴스를 가리키게됨.

       

        history.append(cmd);

        cmd.execute();//DrawCommand execute 메소드가 실행됨.

 

위의 append라는 메소드를 통해서 일단 현재 점 찍는 위치는 저장해둡니다.(명령 첫번째)

 

그리고 cmd.execute라는 메소드로 점을 실제로 찍게되는데 이때 점을 찍으라고 시키는

 

놈과 찍는 놈은 분리시켜놨습니다.

 

시키는놈은 DrawCommand 찍는놈은 DrawCanvas입니다. 그래서 결국 점을 찍게되는데

 

점을 찍을 때 이전에 저장해둔 점도 다찍기 위해서 MacroCommand를 이용해서 점을

 

다 찍게됩니다.

 

 

이해가 안된다면 다음줄만 이해하시면 이 패턴은 끝난겁니다.

 

기본적으로 Command 패턴은 명령을 하는놈과 명령을 수행하는 놈이 나눠져있습니다.

 

그리고 명령을 하는놈은 무조건 execute만 외쳐주면 알아서 수행하는 놈이 하게됩니다.

 

그리고 명령은 종류가 많을 수 있지만 명령 하는놈은 execute만 외치면 그때그때

 

상황에 맞는 것을 알아서 수행하게 됩니다.

 

블로그 이미지

가카리

소프트웨어와 하드웨어 프로그래밍, 취업 및 직장생활 전문 블로그

Proxy 패턴

 

 

이름

해설

Printer

이름있는 프린터를 나타내는 클래스(본인)

Printable

Printer PrinterProxy 공통의 인스턴스

PrinterProxy

이름있는 프린터를 나타내는 클래스(대리인)

Main

동작 테스트용 클래스

 

 

 

 

 

 

 

 

Printable 인터페이스

 

package kch;

public interface Printable {

          

           public abstract void setPrinterName(String name);//이름의 설정

           public abstract String getPrinterName();//이름의 취득

           public abstract void print(String string);//문자열 표시

          

}

 

 

Printer 클래스

 

package kch;

 

public class Printer implements Printable{

 

           private String name;

           public Printer(){//사용안했음

                     heavyJob("Printer의 인스턴스를 생성 중");

           }

           public Printer(String name){                                                //생성자

                     this.name = name;

                     heavyJob("Printer의 인스턴스 (" + name + ")을 생성중");

           }

          

           @Override

           public void setPrinterName(String name) {//이름의 설정(사용안했음)

                     // TODO Auto-generated method stub

                     this.name = name;

           }

 

           @Override

           public String getPrinterName() {                                          //이름의 취득(사용안했음)

                     // TODO Auto-generated method stub

                     return name;

           }

 

           @Override

           public void print(String string) {                                          //이름을 붙여서 표시

                     // TODO Auto-generated method stub

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

                     System.out.println(string);

           }

 

           private void heavyJob(String msg){               //무거운 일

                     System.out.println(msg);

                    

                     for(int i = 0 ; i < 5; i++){

                    

                                try{

                               

                                          Thread.sleep(1000);

                               

                                }catch(InterruptedException e){

                               

                                }

                                System.out.print(".");

                     }

                      System.out.println("완료. ");

           }

}

 

 

PrinterProxy 클래스

 

package kch;

 

public class PrinterProxy implements Printable{

 

           private String name;

           private Printer real;

          

           public PrinterProxy(String name){                                        //생성자

                    

                     this.name = name;

                    

           }

          

           @Override

           public synchronized void setPrinterName(String name) {//이름의 설정, 가벼운 일

                     // TODO Auto-generated method stub

                    

                     if(real != null){

                                real.setPrinterName(name);//'본인'에게도 설정한다.

                     }

                     this.name = name;

           }

 

           @Override

           public String getPrinterName() {                     //이름을 가져옴, 가벼운 일

                     // TODO Auto-generated method stub

                     return name;

           }

 

           @Override

           public void print(String string) {                     //표시, 무거운 일

                     // TODO Auto-generated method stub

                    

                     realize();

                     real.print(string);//Hello world.string 들어있음.

                    

           }

 

           private synchronized void realize(){             //'본인'을 생성

                     if(real == null){

                                real = new Printer(name);//생성자에 무거운일이 포함되있음(5초나 걸리는일)

                     }

           }

}

 

 

Main 클래스

 

package kch;

 

public class Main {

           public static void main(String[] args){

                     Printable p = new PrinterProxy("Alice");

                    

                     System.out.println("이름은 현재 " + p.getPrinterName() + "입니다.");

                     p.setPrinterName("Bob");

                     System.out.println("이름은 현재 " + p.getPrinterName() + "입니다.");

                     p.print("Hello, world.");

           }

 

}

 

 

 

결과화면

 

 

Proxy 패턴은 빠르고 쉽게 처리하는것은 대리인(Proxy)이 처리하고 오래 걸릴것 같은 일은 실제 본인이 처리하게 합니다.

 

여기서 대리인은 PrinterProxy이고 본인은 Printer 클래스입니다.

 

이름을 설정하고 가져오는 가벼운일은 PrinterProxy가 하지만 정작 Print라는 무거운일을 할때는 Print 클래스를 생성하고 처리하게 됩니다.

 

워드를 실행할때 필요한 그림객체나 도형객체를 모두 불러오게 되면 그만큼 로딩속도가 느려지게 됩니다. 하지만 필요할때마다 그림객체를 불러오게된다면 그만큼 로딩속도를 줄일 수 있겠죠.

 

 

블로그 이미지

가카리

소프트웨어와 하드웨어 프로그래밍, 취업 및 직장생활 전문 블로그

 

 

 

이름    

해설

BigChar

큰문자를 나타내는 클래스

BigCharFactory

BigChar의 인스턴스를 공유하면서 생성하는 클래스

BigString

BigChar를 모아서 만든 큰 문자열을 나타내는 클래스

Main

동작 테스트용 클래스

 

 

BigChar 클래스

 

package kch;

 

import java.io.BufferedReader;

import java.io.FileReader;

import java.io.IOException;

 

public class BigChar {

                    

           //문자의 이름

           private char charname;

          

           //큰 문자를 표현하는 문자열('#' '.' '\n'의 열)

           private String fontdata;

          

           //생성자

           public BigChar(char charname){

                     this.charname = charname;

                    

                     try{

                                BufferedReader reader = new BufferedReader(

                                                     new FileReader("big" + charname + ".txt"));

                                String line;

                                StringBuffer buf = new StringBuffer();//파일의 모든 정보는 buf 들어감

                                while((line = reader.readLine()) != null){//다음줄이 있다면?

                                         

                                          buf.append(line);

                                          buf.append("\n");//한줄읽고

 

                                }

                               

                                reader.close();//파일 닫고

                                this.fontdata = buf.toString();//파일에 모든정보를 출력하게됨.

                               

                     }catch(IOException e){//만약 파일이 없다면

                                this.fontdata = charname + "?";

                     }

                    

           }

          

           public void print(){//파일의 정보를 출력하는 메소드

                    

                     System.out.print(fontdata);

          

           }

                    

}

 

 

BigCharFactory 클래스

 

package kch;

 

import java.util.HashMap;

 

public class BigCharFactory {

 

           //이미 만들어진 BigChar의 인스턴스를 관리

           private HashMap pool = new HashMap();

           //Singleton 패턴 인스턴스가 한개

           private static BigCharFactory singleton = new BigCharFactory();

          

           //생성자

           private BigCharFactory(){

           }

          

           public static BigCharFactory getInstance(){

                     return singleton;

           }

          

           //BigChar의 인스턴스 생성(공유)

           //synchronized 복수의 스레드가 new하는것을 방지하기위해서

           public synchronized BigChar getBigChar(char charname){

                    

                     BigChar bc = (BigChar)pool.get("" + charname);

                    

                    

                     //이부분이 핵심 기존에 이미 인스턴스가 있으면 그것을 다시 쓰고

                     //인스턴스가 없다면 해쉬테이블에 넣어둠.

                     //예를들어 112122 1 2란 인스턴스 2개만 있으면됨 112122 모두 인스턴스 6개를 만들필요가없음.

                     if(bc == null){

                               

                                bc = new BigChar(charname);//큰 숫자를 만들어서

                                pool.put("" + charname, bc);//해쉬테이블에 저장하게됨.

                               

                     }

                     return bc;//큰숫자를 반환

           }

          

}

 

 

BigString 클래스

 

package kch;

 

public class BigString {

          

           //큰문자의 배열

           private BigChar[] bigchars;

           //생성자

           public BigString(String string){//string에는 11221같은 값이 들어옴

                     bigchars  = new BigChar[string.length()];

                    

                     BigCharFactory factory = BigCharFactory.getInstance();

                     for(int i = 0 ;  i < bigchars.length ; i++){

                                bigchars[i] = factory.getBigChar(string.charAt(i));//큰숫자의 모임이 됨 bigchars배열은.

                     }

           }

          

          

           //표시

           public void print(){

                    

                     for(int i = 0; i < bigchars.length; i++){

                                bigchars[i].print();

                     }

           }

          

}

 

Main 클래스

 

package kch;

 

public class Main {

           public static void main(String[] args){

                     if(args.length == 0){

                                System.out.println("Usage : java Main digits");

                                System.out.println("Example: java Main 12123");

                                System.exit(0);

                     }

                    

                     BigString bs = new BigString(args[0]);

                     bs.print();

           }

}

 

 

 

 

컴파일시 유의 할 사항

인자를 넘겨줘야하기때문에 다음과 같이 합니다.

 

 

 

1. RunConfigurations를 누릅니다

 

 

 

2. Arguments 탭으로 가서 Program arguments 11221을 입력하고 Run버튼을 누릅니다.

 

결과화면.

 

 

이번 패턴은 인스턴스의 복수 생성 방지를 위한 패턴입니다. 어차피 같은 인스턴스면 재사용하는게 좋기때문에 가벼운급이라는 뜻의 Flyweight가 되었습니다.

 

핵심 부분은

BigCharFactory 클래스의

public synchronized BigChar getBigChar(char charname){

 

메소드인데 여기서 기존에 존재하는 인스턴스인지 아닌지를 확인한 후 기존에 있으면 기존것을 쓰고 없으면 해쉬테이블에서 추가합니다.

 

이 패턴의 특징은 만약에 11221이 입력되면 1 2라는 인스턴스 2개가 생기는데 1에 색깔을 바꾸게 되면 모든 1의 색깔이 바뀌게 됩니다. 이렇게 하나를 변경시키면 다른것도 모두 변경된다는 점이 특징입니다.

 

 

 

블로그 이미지

가카리

소프트웨어와 하드웨어 프로그래밍, 취업 및 직장생활 전문 블로그

State 패턴

 

이름

해설

State

금고의 상태를 나타내는 인터페이스

DayState

State를 구현하고 있는 클래스, 주간의 상태를 나타낸다.

NightState

State를 구현하고 있는 클래스, 야간의 상태를 나타낸다.

Context

금고의 상태변환를 관리하고 경비센터와 연락을 취하는 인터페이스

SafeFrame

Context를 구현하는 클래스, 버튼이나 화면표시 등의 사용자인터페이스를 갖는다.

Main

동작 테스트용 클래스

 

 

 

 

 

 

State 인터페이스

 

package kch;

 

 

public interface State {//상태를 정의

          

           public abstract void doClock(Context context, int hour);//시간 설정

           public abstract void doUse(Context context);//금고사용

           public abstract void doAlarm(Context context);//비상벨

           public abstract void doPhone(Context context);//일반통화

 

}

 

 

DayState 클래스

 

package kch;

 

public class DayState implements State {

 

           private static DayState singleton = new DayState();

           //주간 상태는 하나만 인스턴스를 만들기 위해서

           //singleton 패턴을 씀.

          

           //그래서 생성자는 private

           private DayState(){

                    

           }

          

           public static State getInstance(){//유일한 인스턴스를 얻는다.

                     return singleton;

           }

          

           @Override

           public void doClock(Context context, int hour) {

                     // TODO Auto-generated method stub

                     if(hour < 9 || 17 <= hour){//이 시간때는 저녁시간이므로.

                                context.changeState(NightState.getInstance());//state 바꾸기위해서 넘겨줌.

                     }

           }

 

           @Override

           public void doUse(Context context) {

                     // TODO Auto-generated method stub

                     context.recordLog("금고사용(주간)");

           }

 

           @Override

           public void doAlarm(Context context) {

                     // TODO Auto-generated method stub

                     context.callSecurityCenter("비상벨 (주간)");

           }

 

           @Override

           public void doPhone(Context context) {

                     // TODO Auto-generated method stub

                     context.callSecurityCenter("일반통화(주간)");

           }

           public String toString(){

                     return "[주간]";

           }

          

}

 

 

NightState 클래스

 

package kch;

 

 

public class NightState implements State{

 

           private static NightState singleton = new NightState();

          

           //인스턴스를 하나만 생성하기 위해서 singleton 패턴을 씀

           //그래서 생성자는 private

           private NightState(){

                    

           }

          

           public static State getInstance(){//유일한 인스턴스를 얻는다.

                     return singleton;

           }

          

           @Override

           public void doClock(Context context, int hour) {//시간설정

                     // TODO Auto-generated method stub

                     if(9 <= hour && hour < 17){//이시간대면 낮시간이므로 바꿔줌.

                                context.changeState(DayState.getInstance());

                     }

           }

 

           @Override

           public void doUse(Context context) {//금고사용

                     // TODO Auto-generated method stub

                     context.callSecurityCenter("비상  : 야간금고 사용!");

           }

 

           @Override

           public void doAlarm(Context context) {//비상벨

                     // TODO Auto-generated method stub

                     context.callSecurityCenter("비상벨 (야간)");

           }

 

           @Override

           public void doPhone(Context context) {

                     // TODO Auto-generated method stub

                     context.recordLog("야간통화 녹음");

           }

 

           public String toString(){

                     return "[야간]";

           }

}

 

 

Context 인터페이스

 

package kch;

 

public interface Context {

          

           public