[Design Pattern] Iterator Pattern
Iterator Pattern
Iterator Pattern은 여러 객체를 보관하고 있는 Aggregate Object가 있을 때 각 구성요소 하나 씩 방문하고자 할때 사용됩니다. 이 때 각 Element 내부를 접근하는 등의 표현은 외부로 노출되지 않습니다. 여기서 Aggregate Object에 대해 정리를 하자면 특정 객체를 하나의 단위로 그룹화 할 목적으로 다른 객체를 포함하는 객체를 입니다.
Iterator Pattern은 구성요소들의 순회가 필요하거나 순회를 위한 일관된 인터페이스가 필요할 때 사용합니다. 또한 전체 구성요소에 대해 모두 알 필요없이 각 구성요소에 접근하기 위해서 사용되기도 합니다.
'Head First Design Pattern' 도서에서 소개하고 있는 예시를 사용해 설명하려 합니다.
Problem
마을에 인접한 두 식당이 하나로 합치기로 하였습니다. 각 식당의 사장님들은 메뉴의 통일성을 위해 메뉴판을 새로 작성하게 되었습니다. 메뉴판에는 메뉴의 이름, 설명, 채식자를 위한 식단인지, 가격을 포함시키기로 하였습니다. A식당은 지금까지 메뉴를 ArrayList를 이용하여 관리했으며 B 식당은 Array를 이용하여 관리하고 있었습니다. 메뉴에 포함될 내용만 통일하였지 각자 사용하던 방식은 그대로 유지하려 합니다. 이 때 새로이 고용된 웨이터는 각 메뉴를 알기 위해 ArrayList와 Array로 관리되던 각각의 메뉴를 모두 각 콜렉션의 형태를 익혀서 사용해야만 합니다. 위 상황에 대해서 처음 구현된 상황을 보시죠. 코드는 아래 URL에 있습니다.
Main.java에도 명시해 놓았듯이 해당 프로젝트의 문제는 무엇인가요? 다시 정리해보겠습니다.
1. 이 프로젝트는 인터페이스로 구현되어 있지않습니다.
2. 만약 MenuItem을 관리하는 방식이 Array에서 HashTable 등으로 변경된다면 해당 수정이 웨이터에게 직접적인 영향을 줌으로서 문제가 발생합니다.
3. 메뉴를 출력하는 웨이터는 어떻게 각 메뉴를 보여줄 수 있을지 내부 콜렉션의 구조를 알아야 합니다.
4. 중복된 코드들이 존재합니다.
위와 같은 문제들이 있습니다. 글의 처음에 설명드렸듯이 MenuItem이란 특정 객체를 출력하기 위해 순회하고자 합니다. 다시 한번 말씀드리면 Iterator Pattern은 구성요소들의 순회가 필요하거나 순회를 위한 일관된 인터페이스가 필요할 때 사용합니다. 또한 전체 구성요소에 대해 모두 알 필요없이 각 구성요소에 접근하기 위해서 사용되기도 합니다. 웨이터는 ArrayList, Array, HashTable 등 아무것도 관심없고 MenuItem만 알고 출력해 주고싶을 뿐입니다. 이런 경우 Iterator Pattern을 사용하면 구조를 개선할 수 있습니다.
아래 Iterator Pattern을 적용한 개선된 구조에 대한 코드입니다.
Iterator 인터페이스를 이용하였으며 각 식당은 자신에게 맞는 Iterator를 생성해서 웨이터에게 전달해줍니다. 웨이터는 Iterator 인터페이스만 알 뿐 이제 Array, ArrayList 등에 대해 알 필요가 없어졌습니다. 만약 HashTable로 변경한다하여도 영향이 없습니다. 또한 순회도 가능하며 메뉴출력을 위한 중복된 코드도 제거되었습니다.
Iterator 패턴에서 가장 중요하게 SRP(Single Responsibility Principle), 단일책임의 원칙입니다. 앞선 예제에서는 각 클래스가 Aggregate와 Iteration을 위한 2개의 책임을 가지고 있었다면 Iterator Solving 예제에선 각 책임을 분리함으로서 Cohesion을 높였습니다. Java 언어에서는 내부적으로 Iterator 인터페이스를 제공하기에 해당 인터페이스를 사용하여 구현하여도 무방합니다. 이와 같은 디자인패턴은 정해진 것이 아니라 항상 변형가능하고 융통성있게 사용할 수 있어야 합니다.
지금까지 간략히 Iterator Pattern에 대해 정리하였습니다. 읽어주셔서 감사합니다.