컴포지트 패턴 : 객체를 트리구조로 구성해서 부분-전체 계층 구조를 구현하는 패턴
이 패턴을 사용하면 전체 구조 내의 복합 객체와 개별 객체를 똑같은 방법으로 다룰 수 있게 됩니다.
컴퓨터 부품들이 여러 개 모여서 컴퓨터가 되듯이, 컴퓨터와 부품들의 객체를 하나로, 또 따로 접근할 수 있게 됩니다.
컴퓨터 부품을 예로 들어보겠습니다.
컴퓨터 전체 부품의 추상 클래스입니다.
메소드는 구현하지 않고, 정의되지 않은 채로 사용하게 되면 UnsupportedOperationException
예외를 일으킵니다.
abstract class ComputerComponent { void add(ComputerComponent computerComponent) { throw new UnsupportedOperationException(); } // remove는 이번에 쓰이지는 않습니다. void remove(ComputerComponent computerComponent) { throw new UnsupportedOperationException(); } ComputerComponent getChild(int index) { throw new UnsupportedOperationException(); } String getInfo() { throw new UnsupportedOperationException(); } void print() { throw new UnsupportedOperationException(); } }
부품의 하위 정보들을 담을 클래스입니다.
예를 들면 CPU의 제작사는 Intel, Amd가 있죠.
class Component extends ComputerComponent { String info; public Component(String info) { this.info = info; } // 각 하위 객체의 print() @Override void print() { System.out.println("> " + this.info + "\n"); } }```
컴퓨터 클래스입니다.
부품들이 모이면 컴퓨터가 되죠.
자식을 가지는 객체를 이 클래스로 생성하면, 자식을 리스트로 쉽게 추가, 관리할 수 있습니다.
class Computer extends ComputerComponent { List<ComputerComponent> computerComponents = new ArrayList<>(); String info; public Computer(String info) { this.info = info; } @Override void add(ComputerComponent computerComponent) { this.computerComponents.add(computerComponent); } @Override void remove(ComputerComponent computerComponent) { this.computerComponents.remove(computerComponent); } @Override ComputerComponent getChild(int index) { return computerComponents.get(index); } @Override String getInfo() { return this.info; } @Override void print() { System.out.println(" *" + getInfo() + "*"); System.out.println("-------------"); for (ComputerComponent item : computerComponents) { item.print(); } } }
public class CompositePattern { public static void main(String[] args) { ComputerComponent CPU = new Computer("CPU"); ComputerComponent RAM = new Computer("RAM"); ComputerComponent SDD = new Computer("SDD"); // 컴퓨터 부품 전체 모음(루트 노드) ComputerComponent desktop = new Computer("컴퓨터 부품"); desktop.add(CPU); desktop.add(RAM); desktop.add(SDD); CPU.add(new Component("Intel")); CPU.add(new Component("Amd")); RAM.add(new Component("Samsung")); RAM.add(new Component("SK Hynix")); desktop.print(); // -- 1 desktop.getChild(0).print(); // -- 2 desktop.getChild(0).getChild(0).print(); // -- 3 }
'컴퓨터 부품'이라는 객체를 루트 노드로 만들고,
'컴퓨터 부품'에 'CPU', 'RAM', 'SDD' 자식 객체를 추가하고,
또 'CPU'에 자식 객체 'Intel"과 'Amd"를 추가했습니다.
1번 결과 출력
2번 결과 출력
3번 결과 출력
이처럼 객체의 전체 또는 부분을 접근할 수 있게 되었습니다.
- 객체들이 모두 같은 타입으로 취급되기 때문에 새로운 클래스 추가가 용이합니다.
- 단일객체, 집합객체 구분하지 않고 코드 작성이 가능합니다.
- 설계를 일반화 시켜 객체간의 구분, 제약이 힘듭니다.