캠핑과 개발

오늘 공부한 패턴은 Iterator 패턴이다. Iterator패턴이란 사전적 의미로는 반복자이다.
책에 쓰인 정의로는 컬렉션 구현 방법을 노출시키지 않으면서도 그 집합체 안에 들어있는 모든 항목에 접근할 수 있게 해주는 방법을 제공해준다라고 되어 있다.

쉬운 예로 게시판을 예로 들어보자. 게시물의 들어가는 모든 내용(제목, 작성자, 내용, 등록을 등.)을 Board라는 객체를 만들어서 한번에 담아서 사용한다고 가장을 한다고 하면 대충 Board.java 안에는 이런 코드가 들어갈 것이다.

Board.java
package hmj.pattern.Iterator;

public class Board {
   
    private String name;
    private String subject;
    private String contents;
    private String registeDate;
   
    public Board(){}
    public Board(String name, String subject, String contents, String registeDate){
        this.name = name;
        this.subject = subject;
        this.contents = contents;
        this.registeDate = registeDate;
    }
   
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSubject() {
        return subject;
    }
    public void setSubject(String subject) {
        this.subject = subject;
    }
    public String getContents() {
        return contents;
    }
    public void setContents(String contents) {
        this.contents = contents;
    }
    public String getRegisteDate() {
        return registeDate;
    }
    public void setRegisteDate(String registeDate) {
        this.registeDate = registeDate;
    }   
}


일반적으로 게시판에 들어가는 내용은 저정도일리 없겠지만 Iterator 패턴을 설명하기에는 부족함이 없을꺼 같다. 다른 두사람이 각기 다른 게시판의 리스트를 불러오는 작업을 했다고 가정을 하자. 

A라는 사람은,
public ArrayList<Board> getList() throws Exception { /* 리스트를 불러오기 위한 로직 */ } 을 사용하고

또 다른 B라는 사람은,
public Board[] getList() throws Exception { /*  리스트를 불러오기 위한 로직 */ } 을 사용하였다.

이런식으로 넘겨 받은 객체들은 View페이지에서 각기 리턴형식이 다르기 때문에 서로 다른 형식으로 루프를 돌면서 객체를 꺼내와야 될것이다. 그안에 들어있는 객체는 똑같이 Board형식인 객체인데 말이다. 그리고 또 C가 나타나서 또 다른 방법으로 리스트 목록을 불러오는 메소드를 만든다면 또 다른 방법으로 그 객체를 가져와야 할것이다. 이런 방법은 정말 불편할것이다. 또한 코드 관리 및 확장도 어려울 것이다.

디자인 원칙중에는 "바뀌는 부분을 캡술화 하라" 라는 디자인 원칙이 있다.
위에 리스트 목록을 불러오기 위해서 각기 서로 다른 방법으로 Board 객체를 불러와서 리스트 페이지에 뿌려준다. 이렇게 서로 다른 방식으로 객체를 가져오는 부분을 캡술화를 할수 있을까?

Iterator iterator = NoticeBoardFacade.createIterator();
while(iterator.hasNext()){
    Board board = (Board)iterator.next();
}

이런식으로 Iterator라는 객체를 만들어서 사용하면 어떨까? 리스트 목록을 Iterator라는 객체에 담아서 Iterator 내부에서 ArrayList이건 Board[] 배열이건 캡술화 해서 가져오게 하면 되지 않을까? 된다.. 이게 바로 Iterator 패턴이다..

모르겠으면 일단 한번 해보면 될것 아닌가? 열번 듣는것보다 한번 소스를 보는게 낫고 직접 타이핑을 해보면 더욱 좋다. 내가 그런게 아니고 다들 그러더라.. ㅡㅡ;
소스 코드를 보기 전에 가장 먼저 알아야 할것은 Iterator라는 인터페이스에 의존한다는 점이다.

Iterator.java
/*
 * @(#)Iterator.java
 * Copyright (c) 2000~ NowOnPlay.com inc., All rights reserved.
 * Total E-Business Group, http://www.nowonplay.com
 *
 * 최초작성일자 : April 14, 2008 (hmjkor@nowonplay.com)
 * 수정이력 :
 */
package hmj.pattern.Iterator.Iterator;

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

일단 이렇게 인터페이를 만들어 두면 그 어떤 종류의 객체 컬렉션도 알맞게 구현하여 반복자를 구현 할 수가 있다.

그럼 Iterator 인터페이스를 구현한 클래스 또한 봐야 이해가 갈것이다. 그럼 보자

NoticeBoardIterator.java
/*
 * @(#)NoticeBoardIterator.java
 * Copyright (c) 2000~ NowOnPlay.com inc., All rights reserved.
 * Total E-Business Group, http://www.nowonplay.com
 *
 * 최초작성일자 : April 14, 2008 (hmjkor@nowonplay.com)
 * 수정이력 :
 */
package hmj.pattern.Iterator.board;

import hmj.pattern.Iterator.Board;
import hmj.pattern.Iterator.Iterator.Iterator;

public class NoticeBoardIterator implements Iterator {
    
    private Board[] boards;
    private int position = 0;
    
    /**
     * 생성자
     * @param boards
     */
    public NoticeBoardIterator(Board[] boards) {
        // TODO Auto-generated constructor stub
        this.boards = boards;
    }
    
    /**
     * 해당 배열에 다음 객체가 있는지 여부를 리턴한다.
     */
    public boolean hasNext() {
        // TODO Auto-generated method stub
        if(position >= boards.length || boards[position] == null){
            return false;
        }else{
            return true;
        }        
    }
    
    /**
     * 해당 포지션에 대한 객체를 가져오고 해당 위치에 해당하는 포지션을 다음 포지션으로
     * 이동 시키기 위해  1 더해준다.
     */
    public Object next() {
        // TODO Auto-generated method stub
        Board board = boards[position];
        position = position + 1;
        return board;
    }
}

코드가 그리 어렵지 않아서 자세하진 않지만 간단한 주석만 봐도 알수 있을것이다.
Iterator 인터페이를 구현하여 hasnext(), next() 메소드를 정의해줬다. hasnext()메소드는 Board[]배열에 현재 위치값에서 다음 값이 있는지를 나타내는 메소드이고, next() 메소드는 현재 포지션의 객체를 리턴하고 다음 객체를 얻기 위해 포지션을 1 증가 시키는 메소드이다.

그럼 NoticeBoardFacade 에서는  public Board[] getList() {  ..코드 ..} 이런식으로 넘겨줬던 코드를 Iterator에 맞게 다시 수정을 해야 할것이다. 다음과 같이 말이다.

public Iterator createIterator() {
    /* boards 객체를 가져오기 위한 코드 */
    return new NoticeBoardIterator(boards);
}

이런식으로 넘겨 받은 객체를 View 페이지에서는 간단하게

Iterator iterator = NoticeBoardFacade.createIterator();
while(iterator.hasNext()){
    Board board = (Board)iterator.next();
    board.getName();
    board.getSubject();
    .
    .
}

위와 같은 식으로 사용하면 된다. 이렇게 되면 사용자들은 내부에서는 어떻게 돌아가는지 알지 못해도 간단하게 사용 할 수가 있다. 이게 바로 Iterator 패턴인다.
내용은 그리 어렵지 않은데 설명은 무척이나 길게 한듯하다..ㅠㅠ
오늘도 패턴 하나를 알았다. 패턴 정말 재미있어진다.