2015년 9월 10일 목요일

클래스 디자인 패턴 9. iterator pattern_

1. 개념잡기
  1) 의미 및 구현방법
      for 문이나 기타 반복문을 클래스단위로 쪼갤수 있습니다.
        장점은 for문 도배를 피할수 있다는거고(복잡도를 나눈다)
        단점은 클래스가 많아지는점?
      요건 다른것과 틀리게 패턴으로 한번 봐둬야 일할때
        헷갈림 방지가 가능합니다.

      for 문의 i 의 기능을 추상화해서 일반화 하는걸 Iterator pattern
        이라고도 표현하기도 합니다.
       

  2) 참고자료


2. 소스
  1) 이터레이터 interface와 그 구현체를 작성한다.
      반복역할을 직접 담당하는 이터레이터는 hasNext(체크)
      next(객체 선택) 메서드를 구현하도록 강요하여
      배열로 집어넣은 객체를 처음부터 끝까지 뒤져볼 수 있도록
     합니다.

 
package iterator;

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


 
package iterator;

import serviceMenu.MenuItem;


public class DinerMenuIterator implements Iterator{
 MenuItem[] items;
 int position=0;
 
 public DinerMenuIterator(MenuItem[] items){
  this.items=items;
 }
  
 @Override
 public boolean hasNext() {
  if(position >= items.length || items[position] == null){
   return false;
  }else {
   return true;
  }
   
 }

 @Override
 public Object next() {
  MenuItem menuItem = items[position];
  position = position +1;
  return menuItem;
 }

}

 
package iterator;

import serviceMenu.MenuItem;


public class PancakeHouseMenuIterator implements Iterator{
 MenuItem[] items;
 int position=0;
 
 public PancakeHouseMenuIterator(MenuItem[] items){
  this.items=items;
 }
  
 @Override
 public boolean hasNext() {
  if(position >= items.length || items[position] == null){
   return false;
  }else {
   return true;
  }
   
 }

 @Override
 public Object next() {
  MenuItem menuItem = items[position];
  position = position +1;
  return menuItem;
 }
}


  2) aggregate 는 집합체 구성원을 추가하거나 정보를 관리하는
      역할을 담당합니다. interface를 통해서 Iterator를 반환하는
      메서드를 강제하도록 작성하고
     각 구현체에서 여기에 집합객체를 넣도록 구현합니다.
     여기까지 진행된다면 각 구현체가 Iterator 객체의
       어떤 구현체를 사용할 건지 정할 수 있습니다.

 
package menu;

import iterator.Iterator;
import serviceMenu.MenuItem;

public interface MenuAggr {
 public Iterator createIterator();
}

 
package menu;

import serviceMenu.MenuItem;
import iterator.DinerMenuIterator;
import iterator.Iterator;

public class DinerMenu implements MenuAggr{
 static final int MAX_ITEMS =6;
 int numberOfItems = 0;
 MenuItem[] menuItems;
 
 public DinerMenu(){
  menuItems = new MenuItem[MAX_ITEMS];
  
  addItem("diner1","dier1des",true,2.99);
  addItem("diner2","dier2des",false,3.99);
  addItem("diner3","dier3des",true,2.49);
  addItem("diner4","dier4des",true,3.97);
 }
 
 public void addItem(String name, String description, boolean vegetarian, double price){
  MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
  if(numberOfItems >= MAX_ITEMS){
   System.out.println("더이상 메뉴를 추가할 수 없음");
  }else{
   menuItems[numberOfItems] = menuItem;
   numberOfItems = numberOfItems +1;
  }
 }
 
 public MenuItem[] getMenuItems(){
  return menuItems;
 }
 
 public Iterator createIterator(){
  return new DinerMenuIterator(menuItems);
 }
}

 
package menu;

import iterator.DinerMenuIterator;
import iterator.Iterator;
import java.util.ArrayList;
import serviceMenu.MenuItem;

public class PancakeHouseMenu implements MenuAggr{
 static final int MAX_ITEMS =6;
 int numberOfItems = 0;
 MenuItem[] menuItems;
 
 public PancakeHouseMenu(){
  menuItems = new MenuItem[MAX_ITEMS];
  
  addItem("cake1","cake1des",true,2.99);
  addItem("cake2","cake2des",false,3.99);
  addItem("cake3","cake3des",true,2.49);
  addItem("cake4","cake4des",true,3.97);
 }
 
 public void addItem(String name, String description, boolean vegetarian, double price){
  MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
  if(numberOfItems >= MAX_ITEMS){
   System.out.println("더이상 메뉴를 추가할 수 없음");
  }else{
   menuItems[numberOfItems] = menuItem;
   numberOfItems = numberOfItems +1;
  }
 }
 
 public MenuItem[] getMenuItems(){
  return menuItems;
 }
 
 public Iterator createIterator(){
  return new DinerMenuIterator(menuItems);
 }
}


  3) 객체 하나에 대한 정보를 관리하는 대상객체를 작성합니다.
      여기에는 get 함수만 활용하도록 강제합니다.
      set은 따로 관리하지 않고 생성자에서 생성시 들어가도록
      관리합니다.

 
package serviceMenu;

public class MenuItem {
 String name;
 String description;
 boolean vegetarian;
 double price;
 
 public MenuItem(String name, String description, boolean vegetarian, double price){
  this.name = name;
  this.description=description;
  this.vegetarian=vegetarian;
  this.price=price;
 }
 
 public String getName() {
  return name;
 }
 public String getDescription() {
  return description;
 }
 public boolean isVegetarian() {
  return vegetarian;
 }
 public double getPrice() {
  return price;
 } 
}


  4) 이들을 묶어서 실제 객체만큼 출력이나 행동을 담당할
      웨이트레스 클래스를 작성합니다.      
 
package testWoker;

import serviceMenu.MenuItem;
import menu.DinerMenu;
import menu.PancakeHouseMenu;
import iterator.Iterator;

public class Waitress {
 PancakeHouseMenu pancakeHouseMenu;
 DinerMenu dinerMenu;
 
 public Waitress(PancakeHouseMenu pancakeHouseMenu, DinerMenu dinerMenu){
  this.pancakeHouseMenu=pancakeHouseMenu;
  this.dinerMenu=dinerMenu;
 }
 
 public void printMenu(){
  Iterator pancakeIterator = pancakeHouseMenu.createIterator();
  Iterator dinerIterator = dinerMenu.createIterator();
  System.out.println("아침");
  printMenu(pancakeIterator);
  System.out.println("점심");
  printMenu(dinerIterator);
 }
 
 private void printMenu(Iterator iterator){
  while(iterator.hasNext()){
   MenuItem menuItem = (MenuItem) iterator.next();
   
   System.out.print(menuItem.getName()+",");
   System.out.print(menuItem.getPrice()+"--");
   System.out.println(menuItem.getDescription());
  }
 }
}


  5) 이를 테스트 해보기 위한 소스
 
package testWoker;

import menu.DinerMenu;
import menu.PancakeHouseMenu;

public class SampleMenu {
 public static void main(String[] args) {
  PancakeHouseMenu cake = new PancakeHouseMenu();
  DinerMenu diner = new DinerMenu();
  Waitress wait = new Waitress(cake, diner);
  wait.printMenu();
 }
}


결과 :  아침
cake1,2.99--cake1des
cake2,3.99--cake2des
cake3,2.49--cake3des
cake4,3.97--cake4des
점심
diner1,2.99--dier1des
diner2,3.99--dier2des
diner3,2.49--dier3des
diner4,3.97--dier4des


3. 다이어그램

  3) 다이어그램
      역시 하단 링크를 참고바랍니다.
      하단 링크에서도 자세하게 설명하고 있습니다.
     http://secretroute.tistory.com/entry/Head-First-Design-Patterns-%EC%A0%9C9%EC%9E%A5-Iterator-%EC%99%80-Composite-%ED%8C%A8%ED%84%B4


4. 연관 있는 패턴들
  1) Visitor 패턴
       Iterator가 집합체 숫자를 세는 패턴이라면
       Visitor는 숫자를 셀때 뭔가 작업을 추가하여
       여러 모여있는 instance에 공통 작업을 부여 할 수 있습니다.

  2) Composite 패턴
       Iterator와 비슷하지만 Composite는 재귀적인 구조로
        작성되므로 비슷한 기능을 하는 다른 패턴입니다.

  3) Factory Method 패턴
       iterator 매서드가 Iterator 인스턴스를 작성시 해당 패턴이
        사용될 수 있습니다.

댓글 없음:

댓글 쓰기