4차산업혁명의 일꾼/웹개발

구조안을 돌아다니며 처리하는 패턴(Iterator, Vsitor, Chain of responsibility)

르무엘 2023. 3. 6. 02:46

박은종의 객체지향 설계를 위한 디자인패턴 with 자바

 

구조안을 돌아다니며 처리하는 패턴(Iterator, Vsitor, Chain of responsibility)

 

Iterator

객체 요소들의 내부 표현방식을 공개하지 않고, 객체에서 되지 않은, 외부에서 객체에 순회하는 객체를 만든다.

 

  • 내부에서 객체의 순차적인 제공을 하지 않음
  • 순회 구현 방식이 다르더라도 동일한 방식(메서드)로 순회 할 수 있게 제공
  • 여러 리스트 객체에 대한 동일한 방식으로 순회하는 방법을 제공하기 위해 순회하는 객체를 따로만듬
  • ConcreteIterator는 리스트를 순회하면서 각 리스트의 요소를 반환하는 메서드도 제공한다.
  • 다양한 순회방법이 제공될 수 있다.
  • 동일한 Aggregate를 구현한 클래스들은 동일한 방식으로 순회할 수 있다.
package com.backend.bakckend.designpattern.state;

interface Iterator {
    boolean hasNext();

    Object next();
}

interface Aggregate {
    public abstract Iterator iterator(int type);

    public int getLength();
}

class Book {
    private String name;

    public Book(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

class Constant {
    public static final int FORWARD = 0;
    public static final int REVERSE = 1;
}

abstract class Factory {
    public final Iterator create(Aggregate list, int type) {
        Iterator iterator = createProduct(list, type);
        return iterator;
    }

    protected abstract Iterator createProduct(Aggregate list, int type);
}

class BookShelf implements Aggregate {
    private Book[] books;
    private int last = 0;
    Factory f = ItertorFactory.getInstance();

    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(int type) {
        if (type == 0) {
            return new BookShelfIterator(this);
        } else {
            return new BookShelfReverseIterator(this);
        }
    }
}

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;
    }
}

class ItertorFactory extends Factory {
    private static ItertorFactory factory = new ItertorFactory();

    private ItertorFactory() {
    }

    public static ItertorFactory getInstance() {
        if (factory == null) {
            factory = new ItertorFactory();
        }
        return factory;
    }

    @Override
    protected Iterator createProduct(Aggregate list, int type) {
        if (type == Constant.FORWARD) {
            return new BookShelfIterator((BookShelf) list);
        } else {
            return new BookShelfReverseIterator((BookShelf) list);
        }
    }
}

class BookShelfReverseIterator implements Iterator {
    private BookShelf bookShelf;
    private int index;

    public BookShelfReverseIterator(BookShelf bookShelf) {
        this.bookShelf = bookShelf;
        this.index = bookShelf.getLength() - 1;
    }

    public boolean hasNext() {
        if (index >= 0) {
            return true;
        } else {
            return false;
        }
    }

    public Object next() {
        Book book = bookShelf.getBookAt(index);
        index--;
        return book;
    }
}

public class IteratorTest {
    public static void main(String[] args) {
        BookShelf bookShelf = new BookShelf(4);
        bookShelf.appendBook(new Book("Around 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(Constant.FORWARD);
        while (it.hasNext()) {
            Book book = (Book) it.next();
            System.out.println("" + book.getName());
        }

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

        it = bookShelf.iterator(Constant.REVERSE);
        while (it.hasNext()) {
            Book book = (Book) it.next();
            System.out.println("" + book.getName());
        }


    }

}

 

 

Vsitor

  • 구조 안을 돌아다니며 일을 함 "방문자"
  • 객체 구조의 요소들이 수행해야할 기능을 모아둔 패턴
  • 각 객체 요소를 변경하지 않고, 기능을 추가할 수 있음
  • 데이터의 구조와 처리를 분리하여 처리하는 부분을 객체로 만들어 각 데이터 구조를 돌아다니며 오퍼레이션이 수행되도록 함
  • 각 데이터는 이러한 visitor를 accept 함
  • 추상구문 트리의 예
  • 문법적 처리를 위해 각 노드마다 수행해야 하는 기능을 따로 정의 해야함

 

  • 여러 요소에 대해 유사한 기능의 메서드를 한곳에 모아서 관리하게 되고, 여러 클래스에 걸친 메서드를 추가하기 용이함
  • 각 클래스에 대한 기능이 자주 변경되거나 알고리즘의 변화가 많을때 사용하는것이 효율적임
  • 새로운 요소 클래스를 추가하게 되면 그에 해당되는 기능을 모든 Visitor에서 구현해하 함
  • 따라서 요소의 변화가 거의 없고 기능의 추가 삭제가 자주 발생할때 사용하는것이 좋음
  • 각 객체의 오퍼레이션이 외부에 노출되는 것이므로 객체지향 프로그래밍의 캡슐화 전략에 위배
  • 주로 Composite 패턴에서 자주 사용될 수 있음

 

Chain of responsibility

  • 책임 떠넘기기
  • 다수의 객체를 사슬처럼 연결
  • 요청을 처리할 수 있는 기회를 하나 이상의 객체에게 부여함
  • 요청을 해결할 객체를 만날 때까지 객체 고리를 따라서 요청을 전달
  • 메세지를 보내는 객체와 이를 받아서 처리하는 객체들 간의 결합도를 줄이기 위함
  • 하나의 요청에 대한 처리가 반드시 한 객체에서만 이루어지는것이 아닌 여러 객체가 조건이 맞으면 처리의 기회를 가지게 됨
  • HELP 시스템 같은 경우 적절한 답을 찾을 때 까지 연결되어 해결할 수 있음
  • 객체들 간의 결합도가 적어진다. 요청을 처리하는 객체와 요청을 보내는 객체가 서로 모를 수 있다.
  • 연결순서는 상황에 따라 바뀌거나 추가 삭제될 수 있다. 즉 객체의 책임을 추가, 변경, 확장할 수 있다.
  • 메세지가 항상 수신된다는것을 보장할 수 없다.

 

 

 

LIST