해당 포스팅은 한빛 미디어 헤드퍼스트 디자인 패턴(에릭 프리먼, 엘리자베스 롭슨 저)를 통해 공부한 내용을 정리한 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
좋은 프로그래머는 자기 두뇌를 사용한다. 그러나 좋은 가이드라인은 모든 케이스를 고려해야만 하는 노력을 줄여준다.
(Francis Glassborow, 개발자)
문제점
각자 다른 자료구조 및 구현 방법이 달라 코드를 통일시킬 수가 없음.
PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
ArrayList<MenuItem> breakfastItems = pancakeHouseMenu.getMenuItems();
DinerMenu dinerMenu = new DinerMenu();
MenuItem[] lunchItems = dinerMenu.getMenuItems();
for (int i = 0; i < breakfastItems.size(); i++) {
MenuItem menuItem = breakfastItems.get(i);
System.out.print(menuItem.getName() + " ");
System.out.println(menuItem.getPrice() + " ");
System.out.println(menuItem.getDescription());
}
for (int i = 0; i < lunchItems.length; i++) {
MenuItem menuItem = lunchItems[i];
System.out.print(menuItem.getName() + " ");
System.out.println(menuItem.getPrice() + " ");
System.out.println(menuItem.getDescription());
}
- PancakeHouse는 메뉴를 List로 관리.
- Diner는 메뉴를 array로 관리
반복을 캡슐화하기
디자인 패턴의 기본: 바뀌는 부분을 캡슐화하라!
Iterator iterator = breakfastMenu.createIterator();
while (iterator.hasNext()) {
MenuItem menuItem = iterator.next();
}
Iterator iterator = lunchMenu.createIterator();
while (iterator.hasNext()) {
MenuItem menuItem = iterator.next();
}
public class PancakeHouseMenuIterator implements Iterator {
List<MenuItem> items;
int position = 0;
public PancakeHouseMenuIterator(List<MenuItem> items) {
this.items = items;
}
public MenuItem next() {
return items.get(position++);
}
public boolean hasNext() {
return items.size() > position;
}
}
public class DinerMenuIterator implements Iterator {
MenuItem[] items;
int position = 0;
public DinerMenuIterator(MenuItem[] items) {
this.items = items;
}
public MenuItem next() {
return items[position++];
}
public boolean hasNext() {
return items.length > position;
}
}
Iterator Pattern
- 반복 작업을 캡슐화
- Iteraotr 인터페이스의 메소드. hasNext(), next()
- 메뉴 구현이 캡슐화되어 있음
- 종업원은 메뉴에서 컬렉션을 어떻게 저장하고 있는지 알 필요가 없음.
- 반복자만 구현한다면 다형성을 활용하여 하나의 반복문으로 처리 가능.
- 종업원은 인터페이스만 알면 됨.
💡 Iterator Pattern
컬렉션의 구현방법을 노출하지 않으면서 집합체 내의 모든 항목에 접근하는 방법 제공.
- 인터페이스와 구현이 간단.
- 각자의 비즈니스 로직만 처리 가능
- 확장 가능성이 좋음
구조
- 공통된 인터페이스를 클라이언트가 참조할 수 있도록 개발.
- 서브 클래스는 인터페이스에 따라 개발.
단일 역할 원칙
- 어떤 클래스가 바뀌는 이유는 하나뿐 이여야 한다.
Iterable 인터페이스
- 어떤 클래스던 Iterable을 구현한다면 그 클래스는 iterator() 메소드를 구현
- Iterator 인터페이스를 구현하는 반복자 리턴
- forEach() 메소드 제공
새로운 문제점
public void printMenu() {
Iterator<MenuItem> pancakeIterator = pancakeHouseMenu.createIterator();
Iterator<MenuItem> dinerIterator = dinerMenu.createIterator();
Iterator<MenuItem> cafeIterator = cafeMenu.createIterator();
System.out.println("메뉴\n----\n아침 메뉴"); printMenu(pancakeIterator);
System.out.println("\n점심 메뉴"); printMenu(dinerIterator);
System.out.println("\n저녁 메뉴");
printMenu(cafeIterator);
}
- 메뉴들이 추가가 되면 OCP(Open-Closed Principle)에 위배됨.
- 메뉴를 한꺼번에 관리할 방법이 필요함.
public class Waitress {
List<Menu> menus;
public Waitress(List<Menu> menus) {
this.menus = menus;
}
public void printMenu() {
Iterator<Menu> menuIterator = menus.iterator();
while(menuIterator.hasNext()) {
Menu menu = menuIterator.next();
printMenu(menu.createIterator());
}
}
void printMenu(Iterator<MenuItem> iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = iterator.next();
System.out.print(menuItem.getName() + ", ");
System.out.print(menuItem.getPrice() + " -- ");
System.out.println(menuItem.getDescription());
}
}
}
Composite Pattern
💡 컴포지트 패턴
객체를 트리구조로 구성해서 부분-전체 계층 구조를 구현. 컴포지트 패턴을 사용하면 클라이언트에서 개별 객체와 복합 객체를 똑같은 방법으로 다룰 수 있음.
- 단일 역할 원칙을 깨는 대신 투명성을 확보하는 패턴
- Component 인터페이스에 자식들을 관리하는 기능과 잎으로써의 기능을 전부 넣어서 클라이언트가 복합 객체와 잎을 똑같은 방식으로 처리할 수 있도록 만들었음.
- 상황에 따라 원칙을 적절하게 사용해야 함.
'기타 > 디자인패턴' 카테고리의 다른 글
[Design Pattern] Proxy Pattern (2) | 2024.06.10 |
---|---|
[Design Pattern] State Pattern (0) | 2024.06.09 |
[Design Pattern] Template Method Pattern (0) | 2024.06.05 |
[Design Pattern] Adapter Pattern (0) | 2024.06.04 |
[Design Pattern] Command Pattern (2) | 2024.06.03 |