아침식사를 파는 식당과 점심식사를 파는 식당을 통합한다고 가정하자. 통합한 식당의 메뉴를 보기위해서는 두 식당에서 파는 메뉴들을 모두 열람할 수 있을 것이다. 하지만, 기존에 메뉴를 저장하는 방식이 다르다면? (ex. 아침식사는 ArrayList에, 점심식사는 배열에 저장) 그렇다면 통합하는 식당이 늘어날때마다 추가해야하는 반복문이 늘어날 것이다.
Iterator iterator = breakfastMenu.CreateIterator();
while(iterator.hasNext()){
MenuItem menuItem = iterator.next();
}
이는 이와 같이 반복 작업 처리방법을 캡슐화한 Iterator
라는 객체를 만들어서 해결할 수 있다.
컬렉션의 구현방법을 노출하지 않으면서 집합체 내의 모든 항목에 접근하는 방법을 제공한다.
객체지향에서 중요한 것은 “바뀌는 부분을 캡슐화하라” 이다. Iterator Pattern에서 사용되는 Iterator 인터페이스는 hasNext()
, next()
의 메서드를 보유하고 있으며, 모든 종류의 객체 컬렉션에 반복자를 구현할 수 있다.
이를 사용하면 집합체 내에서 어떤 식으로 일이 처리되는지 전혀모르는 상태에서 그 안에 들어있는 모든 항목을 대상으로 반복작업을 수행할 수 있다. 또한, 컬렉션 안에 저장되어있는 모든 항목에 접근하는 방식이 통일되어있으므로, 종류에 관계없이 모든 집합체에서 사용할 수 있는 다형적인 코드를 만들 수 있다는 장점도 있다.
집합체에서 내부 컬렉션 관련 기능과 반복자용 메서드 관련 기능을 모두 구현해도 기능상의 문제는 없을 것이다. 하지만, 클래스에서 맡고있는 모든 역할은 추후에 코드에 변화를 유발할 수 있다. 많은 역할을 맡고있을수록 변화해야하는 부분이 많아진다는 의미이다. 그렇기 때문에 하나의 클래스에는 하나의 역할만 부여되어야 하고 이것이 바로 단일 역할 원칙이다.
객체를 트리구조로 구성해서 부분-전체 계층구조를 구현한다. 이를 사용하면 클라이언트에서 개별 객체와 복합객체를 똑같은 방법으로 다룰 수 있다.
위에서 살펴본 식당에 이제는 디저트 메뉴를 추가하려고 한다고 가정하자. 하지만, 현재의 상태로는 추가할 수 없다. 아침식사, 점식식사라는 자료형을 담는 컬렉션만 현재 지원하고 있기 때문에, 디저트라는 자료형이 들어갈 수 없기 때문이다. 이는 Composite Pattern을 사용하여 재귀적인 구현을 통해 해결할 수 있다.
Composite Pattern는 단일 역할 원칙을 깨는 대신 투명성을 확보하는 패턴이다. 여기서 투명성이란, 클라이언트가 복합객체와 리프객체를 동일한 방식으로 처리할 수 있도록 만드는 것이다. 사용하는 클라이언트의 입장에서는 어떤 원소가 복합 객체인지 리프객체인지 투명하게 보인다.