'Design Pattern'에 해당되는 글 4건

  1. 2009.05.06 :: Singleton 패턴
  2. 2009.05.06 :: Template Method패턴
  3. 2009.05.06 :: Adapter 패턴
  4. 2009.05.06 :: Iterator패턴
Design Pattern 2009. 5. 6. 12:28


-지정한 클래?스의 인스턴스가 '절대로' 1개밖에 존재하지 않는 것을 '보증'하고 싶을 때
-인스턴스가 1개밖에 존재하지 않는 것을 프로그램 상에서 표현하고 싶을 때
?

밑줄을 친 것은 static이다.

싱글톤클래스에서는 인스턴스를 1개밖에 만들 수 없으며, singleton은 static필드로서 Singleton클래스의 인스턴스에서 초기화된다. 이 초기화는 Singleton클래스를 로드할 때 1회만 실행된다.
생성자는 private. 외부에서 생성자의 호출을 금지하기 위해서이다!!
인스턴스를 얻는 메소드로 getInstance가 준비되어 있다.

//싱글톤클래스
public class Singleton {
    private static Singleton singleton = new Singleton();
    private Singleton() {                                
        System.out.println("인스턴스를 생성했습니다.");
    }
    public static Singleton getInstance() {
        return singleton;
    }
}

//테스트를 위한 메인클래스
public class Main {
    public static void main(String[] args) {
        System.out.println("Start.");
        Singleton obj1 = Singleton.getInstance();
        Singleton obj2 = Singleton.getInstance();
        if (obj1 == obj2) {
            System.out.println("obj1과 obj2는 같은 인스턴스입니다.");
        } else {
            System.out.println("obj1과 obj2는 같은 인스턴스가 아닙니다.");
        }
        System.out.println("End.");
    }
}


다른 예제


public class TicketMaker {
    private int ticket = 1000;
    private static TicketMaker singleton = new TicketMaker(); //싱글톤객체생성   
    private TicketMaker() {     //생성자                                   
    }                                                              
    public static TicketMaker getInstance() {  //인스턴스를 얻기 위한 메소드
        return singleton;                                          
    }                                                              
    public synchronized int getNextTicketNumber() { //synchronized선언함으로 복수의 스레드에서호출되어도 올바로 작동시키기 위한 조치.사용하지않으면 복수의 스레드에 같은 값 반환 위험.
        return ticket++;
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("Start.");
        for (int i = 0; i < 10; i++) {
            System.out.println(i + ":" + TicketMaker.getInstance().getNextTicketNumber());
        }
        System.out.println("End.");
    }
}

posted by 나는너의힘
:
Design Pattern 2009. 5. 6. 12:27


템플릿의 기능을 가진 패턴.
상위클래스에 템플릿에 해당하는 메소드가 정의, 추상메소드가 사용.
상위 클래스의 프로그램만 보면 추상 메소드를 어떻게 호출하고 있는 알 수 있지만, 최종적으로 어떤 처리가 수행되는지는 알 수 없다.

추상메소드를 실제로 구현하는 것은 하위 클래스다. 서로 다른 하위 클래스가 서로 다른 구현을 하더라도 처리의 큰 흐름은 상위 클래스에서 결정한대로 이루어진다.

(파워포인트2007로 작성...연결선이 맘에들지 않는다.;)

클래스 일람
AbstractDisplay : 추상클래스로서 메소드 display만 구현되고 있다.
CharDisplay : 메소드 open,print,close를 구현
StringDisplay : 위와 같지만 printLine도 추가
Main : 동작 테스트용

//AbstractDisplay
public abstract class AbstractDisplay {  // 추상 클래스 AbstractDisplay
    public abstract void open();         // 하위 클래스에 구현을 맡기는 추상 메소드 (1) open
    public abstract void print();        // 하위 클래스에 구현을 맡기는 추상 메소드 (2) print
    public abstract void close();        // 하위 클래스에 구현을 맡기는 추상 메소드 (3) close
    public final void display() {        // 추상 클래스에서 구현되고 있는 메소드 display
        open();                        // 우선 open하고…
        for (int i = 0; i < 5; i++) {    // 5번 print을 반복하고…
            print();                   
        }
        close();     // … 마지막으로 close한다. 이것이 display 메소드에서 구현되고 있는 내용.
    }
}

//CharDisplay
public class CharDisplay extends AbstractDisplay {  // CharDisplay는 AbstractDisplay의
// 하위 클래스.
    private char ch;                              // 표시해야 할 문자
    public CharDisplay(char ch) {                  // 생성자에서 전달된 문자 ch을
        this.ch = ch;                             // 필드에 기억해 둔다.
    }
    public void open() {                            // 상위 클래스에서는 추상 메소드였다.
        // 여기에서 오버라이드해서 구현.
        System.out.print(“<<”);                     // 개시 문자열“<<”을 표시한다.
    }
    public void print() {                           // print 메소드도 여기에서 구현한다.
// 이것이 display에서 반복해서 호출된다.
        System.out.print(ch);                      // 필드에 기억해 둔 문자를 1개 표시한다.
    }
    public void close() {                           // close 메소드도 여기에서 구현.
        System.out.println(“>>”);                   // 종료 문자열 “>>”을 표시.
    }
}

//StringDisplay
public class StringDisplay extends AbstractDisplay {    // StringDisplay도
// AbstrctDisplay의 하위 클래스.
    private String string;                            // 표시해야 할 문자열.
    private int width;                              // 바이트 단위로 계산한 문자열의 「폭」.
    public StringDisplay(String string) {               // 생성자에서 전달된 문자열 string을
        this.string = string;                           // 필드에 기억.
        this.width = string.getBytes().length;          // 그리고 바이트 단위의 폭도 필드에
       // 기억해 두고 나중에 사용한다.
    }
    public void open() {                             // 오버라이드해서 정의한 open 메소드.
        printLine();                                 // 이 클래스의 메소드 printLine에서
                                                     // 선을 그리고 있다.
    }
    public void print() {                               // print 메소드는
        System.out.println(“|” + string + “|”);     // 필드에 기억해 둔 문자열의
          // 전후에 “|”을 붙여서 표시.
    }
    public void close() {                               // close 메소드는
        printLine();                                    // open 처럼 printLine 메소드에서
                                                       // 선을 그리고 있다.
    }
    private void printLine() {                  // open과 close에서 호출된 printLine 메소드이다.
       // private이기 때문에 이 클래스 안에서만 사용된다.
        System.out.print(「+「);                // 테두리의 모서리를 표현하는”+” 마크를 표시.
        for (int i = 0; i < width; i++) {       // width개의 “-“을 표시하고
            System.out.print(「-「);            // 테두리 선으로 이용한다.
        }
        System.out.println(「+「);              // 테두리의 모서리를 표현하는 “+” 마크를 표시.
    }
}

//Main
public class Main {
    public static void main(String[] args) {
 // 'H'을 가진 CharDisplay 인스턴스를 1개 만든다>
        AbstractDisplay d1 = new CharDisplay('H');
 // “Hello, world.”을 가진 StringDisplay의 인스턴스를 1개 만든다.
        AbstractDisplay d2 = new StringDisplay(“Hello, world.”);
     // “안녕하세요.”를 가진 StringDisplay의 인스턴스를 1개 만든다.
        AbstractDisplay d3 = new StringDisplay(“안녕하세요.”);
        d1.display();   // d1, d2, d3 모두 AbstractDisplay의 하위클래스의 인스턴스이기 때문에
        d2.display();   // 상속한 display메소드를 호출할 수 있다.
        d3.display();   // 실제 동작은 CharDisplay나 StringDisplay에서 결정한다.
    }
}



이 패턴을 이용하면 상위클래스의 템플릿메소드에서 알고리즘이 기술되어 있으므로, 하위 클래스측에서는 알고리즘을 일일이 기술할 필요가 없다.

상위클래스에서 하위 클래스에게 요청

-상위클래스에서 정의되어 있는 메소드를 하위클래스에서 이용할 수 있다
-하위클래스에 약간의 메소드를 기술해서 새로운 기능을 추가할 수 있다
-하위클래스에서 메소드를 오버라이드하면 동작을 변경할 수 있다.


추상클래스의 의의
추상메소드는 본체가 기술되어 있지 않아서 구체적인 처리내용을 알 수 없으나, 메소드의 이름을 결정하고 메소드를 사용한 템플릿메소드에 의해 처리를 기술하는 것은 가능하다.
실제의 처리 내용은 하위 클래스에서 결정하지만, 추상클래스의 단계에서 처리의 흐름을 형성하는 것은 중요하다.
posted by 나는너의힘
:
Design Pattern 2009. 5. 6. 12:25


예를 들어 직류 12볼트로 작동하는 노트북을 교류100볼트의 AC전원에 연결한다고 가정하자.
이때 우리는 AC어댑터라는 장치를 사용한다. AC어댑터는 교류100볼트를 직류12볼트로 교환해 준다.

교류100볼트------AC어댑터--------직류12볼트

상속을 사용한 Adapter패턴



제공되고 있는 것 / 교류 100볼트 / Banner클래스
교환장치 / 어댑터 / PrintBanner 클래스
필요한 것 / 직류 12볼트 / Print인터페이스


//Print 클래스
public interface Print {

    public abstract void printWeak();
    public abstract void printStrong();
}

//PrintBanner클래스
public class PrintBanner extends Banner implements Print {
    public PrintBanner(String string) {
        super(string); //super는 Banner클래스의 생성자를 가리킴
    }
    public void printWeak() {
        showWithParen();
    }
    public void printStrong() {
        showWithAster();
    }
}

//Banner클래스
public class Banner {
    private String string;
    public Banner(String string) {
        this.string = string;
    }
    public void showWithParen() {
        System.out.println("(" + string + ")");
    }
    public void showWithAster() {
        System.out.println("*" + string + "*");
    }
}

//Main클래스
public class Main {
    public static void main(String[] args) {
        Print p = new PrintBanner("Hello");
        p.printWeak();
        p.printStrong();
    }
}

PrintBanner클래스가 어댑터의 역할을 완수한다. 준비된 Banner클래스를 확장해서 showWithParen메소드와 showWithAster메소드를 상속한다. 또한, 필요한 Print인터페이스를 구현해서 printWeak메소드와 printStrong 메소드를 구현한다.
메인클래스는 PrintBanner클래스가 어떻게 실현되고 있는지 모른다. 실행되는지 모른다는 것은 메인 클래스를 전혀 변경하지 않고 PrintBanner클래스의 구현을 바꿀 수 있다는 것..
posted by 나는너의힘
:
Design Pattern 2009. 5. 6. 12:24



Iterator패턴이란, 무엇인가 많이 모여있는 것들을 순서대로 지정하면서 전체를 검색하는 처리를 실행하기 위한 것이다.


1.Aggregate인터페이스

package Iterator.Sample;

public interface Aggregate {
    public abstract Iterator iterator();
}

인터페이스에 선언되어 있는 메소드 iterator 메소드 하나뿐이다. 이 메소드는 집합체에 대응하는 Iterator를 1개 작성하기 위한 것이다
iterator메소드를 사용해서 Iterator인터페이스를 구현한 클래스의 인스턴스를 1개 만든다.

2.Iterator인터페이스

package Iterator.Sample;

public interface Iterator {
    public abstract boolean hasNext();
    public abstract Object next();
}

다음요소가 존재하는지 여부를 위한 hasNext, 존재하면 true반환
다음요소를 얻기위한 next 메소드.. Object타입으로 알 수 있듯 집합체의 요소 1개를 반환.. 또한, 다음 요소를 반환하도록 내부 상태를 다음으로 진행시켜두는 역할을 한다. 여기서는 메소드 이름만.. 구현은 BookShelfIterator

3.Book클래스

package Iterator.Sample;

public class Book {
    private String name;
    public Book(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

책이름 얻기 getName
책이름은 생성자에서 객체를 초기화할 때 인수로 지정한다.

4.BookShelf클래스

package Iterator.Sample;

public class BookShelf implements Aggregate {
    private Book[] books;
    private int last = 0;
    public BookShelf(int maxsize) {
        this.books = new Book[maxsize];
    }
    public Book getBookAt(int index) {
        return books[index];
    }
    public void appendBook(Book book) {
        this.books[last] = book;
        last++;
    }
    public int getLength() {
        return last;
    }
    public Iterator iterator() {
        return new BookShelfIterator(this);
    }
}


서가를 나타내는 클래스.. 이 클래스를 집합체로 다루기 이해 Aggregate를 구현하고 있다.
iterator메소드는 BookShelf클래스에 대응하는 이터레이터로서, BookShelfIterator라는 클래스의 인스턴스를 생성해서 그것을 반환한다. 이 서가의 책을 나열하고 싶을때 iterator메소드를 호출한다.

5.BookShelf클래스

package Iterator.Sample;

public class BookShelfIterator implements Iterator {
    private BookShelf bookShelf;
    private int index;
    public BookShelfIterator(BookShelf bookShelf) {
        this.bookShelf = bookShelf;
        this.index = 0;
    }
    public boolean hasNext() {
        if (index < bookShelf.getLength()) {
            return true;
        } else {
            return false;
        }
    }
    public Object next() {
        Book book = bookShelf.getBookAt(index);
        index++;
        return book;
    }
}

Iterator인터페이스를 구현하고있다.
index는 현재 주목하고 있는 책을 가리킨다.
생성자에서 전달된 BookShelf의 인스턴스를 bookshelf에 저장하고 index를 0으로 한다.
hasNext는 index가 책의 권수 bookShelf.length()값보다 작은지 ,큰지로 판정
next메소드는 현재 처리하고 있는 책을Book의 객체 반환하고, 다시 다음으로 진행시키기 위한 메소드.
우선 반환값으로 반환해야 할 책을 book라는 변수로 저장하고 index를 다음으로 진행시킨다.
6.Main클래스

package Iterator.Sample;

import java.util.*;

public class Main {
    public static void main(String[] args) {
        BookShelf bookShelf = new BookShelf(4);
        bookShelf.appendBook(new Book("Zround the World in 80 Days"));
        bookShelf.appendBook(new Book("Bible"));
        bookShelf.appendBook(new Book("Cinderella"));
        bookShelf.appendBook(new Book("Daddy-Long-Legs"));
        Iterator it = bookShelf.iterator();
        while (it.hasNext()) {
            Book book = (Book)it.next();
            System.out.println(book.getName());
        }
    }
}


bookShelf.iterator()에 의해 얻어지는 it가 서가를 검색하기 위한 이터레이터의 인스턴스이다.
posted by 나는너의힘
: