Composite 패턴
- 컴포짓 패턴은 part-whole의 관계를 갖는 객체들을 정의할때 유용하다.
- 여러 객체가 한 클래스 전체 객체의 일부분으로 정의될때 사용한다. 부분 객체의 추가나 삭제가 있어도 전체 클래스의 코드를 변경하지 않으면 컴포짓 패턴은 유용하다.
- 그리고 클라이언트는 whole과 part를 구분하지 않고 동일한 인터페이스를 가질 수 있다.
컴퓨터에 추가 장치 지원하기
- 컴퓨터를 모델링해보자. 컴퓨터에는 Keyboard, Monitor, RAM, SSD, CPU등이 있다. 각각의 클래스를 정의하고 Computer 클래스는 이들 구성 장치를 포함하는것으로 구성할 수 있다.

javapublic class CPU {
private int price;
private int power;
public CPU(int power, int price) {
this.power = power;
this.price = price;
}
public int getPrice() {
return price;
}
public int getPower() {
return power;
}
}
public class SSD {
// 생략
}
public class VGA {
// 생략
}
public class Computer {
private CPU cpu;
private VGA vga;
private SSD ssd;
public void addCPU(CPU cpu) {
this.cpu = cpu;
}
public void addVGA(VGA vga) {
this.vga = vga;
}
public void addSSD(SSD ssd) {
this.ssd = ssd;
}
public int getPrice() {
int cpuPrice = cpu.getPrice();
int vgaPrice = vga.getPrice();
int ssdPrice = ssd.getPrice();
return cpuPrice + vgaPrice + ssdPrice;
}
public int getoPower() {
int cpuPower = cpu.getPower();
int vgaPower = vga.getPower();
int ssdPower = ssd.getPower();
return cpuPower + vgaPower + ssdPower;
}
}
public class Client {
public static void main(String[] args) {
CPU amd5800x = new CPU(105, 60);
VGA gtx3080 = new VGA(200, 200);
SSD wd500 = new SSD(5, 15);
Computer computer = new Computer();
computer.addCPU(amd5800x);
computer.addVGA(gtx3080);
computer.addSSD(wd500);
int computerPrice = computer.getPrice();
int computerPower = computer.getoPower();
System.out.println("Total price: " + computerPrice);
System.out.println("Consume power: " + computerPower);
}
}
문제점
- 다른 부품을 추가할 때는 어떻게?
- 만약 새로운 부품을 추가하려면 다음과 같이 수정해야한다.
- 새로운 붚무에 대한 참조를 필드로 추가한다
- 새로운 부품에 객체를 설정하는 setter로 addHDD같은 메소드를 추가한다
- 부품의 메소드를 이용하는 모든 메소드에서 새로 추가된 부품 객체를 추가한다.
- 새로운 부품이 추가될때마다 기존 코드를 지속적으로 수정해야한다.
해결책
- 앞의 코드는 부품의 변화에 따라 Computer클래스의 코드도 변화할 수 밖에 없는 문제를 갖고 있다.
- 구체적인 부품들을 일반화한 클래스를 정의하고 이를 Computer클래스가 가리키게 하는 것이 올바른 설계다.

- 주요 개선점은 다음과 같다
- Computer가 가질 수 있는 부품들을 일반화해 ComputerDevice라는 클래스를 정의한다.
- ComputerDevice클래스는 구체적인 부품 클래스의 공통 기능만 가진다.
- ComputerDevice 객체를 실재로 인스턴스 할 수 없다. (추상 클래스)
- 구체적인 부품은 ComputerDevice를 구현한다.
- Computer클래스 역시 ComputerDevice의 하위 클래스다.
javapublic abstract class ComputerDevice {
public abstract int getPrice();
public abstract int getPower();
}
public class CPU extends ComputerDevice {
//...
}
public class VGA extends ComputerDevice {
//...
}
public class SSD extends ComputerDevice {
//...
}
public class Computer extends ComputerDevice {
private List<ComputerDevice> components = new ArrayList<ComputerDevice>();
public void addComponent(ComputerDevice component) {
components.add(component);
}
public void removeComponent(ComputerDevice component) {
components.remove(component);
}
public int getPrice() {
int price = 0;
for (ComputerDevice component : components) {
price += component.getPrice();
}
return price;
}
public int getPower() {
int power = 0;
for (ComputerDevice component : components) {
power += component.getPower();
}
return power;
}
}
- 이제 Computer클래스에 새로운 부품을 추가해 Computer를 확장하려고 할 때 Computer클래스 코드는 변경할 필요가 없다.
- 일반화된 부품을 의미하는 ComputerDevice를 이용하기 때문이다.
- 새로운 부품인 NIC를 추가하더라도 ComputerDevice의 하위 클래스로 구현하면된다.