컴포짓 패턴은 구조패턴 중 하나로 클라이언트 입장에서는 '전체'나 '부분'이나 모두 동일한 컴포넌트로 인식할 수 있는 계층구조를 만든다.
의도는 트리 구조로 작성하여, 부분-전체 관계(Part-Whole Hierarchy)를 표현하는 것입니다.
컴포짓 패턴의 구조는 아래와 같습니다.
Component Interface
Leaf Class
Composite Class
가방에 들어있는 아이템의 가격을 출력하는 예제를 들어봅시다.
컴포짓 패턴을 적용하면 가방객체는 Composite Class가 되고, 아이템객체는 Leaf Class가 됩니다.
컴포짓 패턴 적용 전 코드를 살펴봅시다.
public class Item {
private String name;
private int price;
public Item(String name, int price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
public class Bag {
List<Item> items;
public Bag() {
items = new ArrayList<>();
}
public List<Item> getItems(){
return this.items;
}
public void add(Item item){
items.add(item);
}
}
public class Client {
public static void main(String[] args) {
Item doranBlade = new Item("도란검", 450);
Item healPotion = new Item("체력 물약", 50);
Bag bag = new Bag();
bag.add(doranBlade);
bag.add(healPotion);
Client client = new Client();
client.printPrice(doranBlade);
client.printPrice(bag);
}
private void printPrice(Bag bag) {
System.out.println(bag.getItems().stream()
.mapToInt(Item::getPrice)
.sum());
}
private void printPrice(Item item) {
System.out.println(item.getPrice());
}
}
위와같이 Bag안에 여러 아이템이 존재하는 트리구조가 만들어집니다.
하지만 printPrice가 단일객체와 복합 객체가 다른 방법으로 처리되는 형태가 만들어집니다.
컴포짓 패턴을 적용해봅시다.
public interface Component {
int getPrice();
}
public class Item implements Component{
private String name;
private int price;
public Item(String name, int price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
public class Bag implements Component {
List<Component> components;
public Bag() {
components = new ArrayList<>();
}
public List<Component> getComponents() {
return this.components;
}
public void add(Component component) {
components.add(component);
}
@Override
public int getPrice() {
return this.components.stream()
.mapToInt(Component::getPrice)
.sum();
}
}
public class Client {
public static void main(String[] args) {
Item doranBlade = new Item("도란검", 450);
Item healPotion = new Item("체력 물약", 50);
Bag bag = new Bag();
bag.add(doranBlade);
bag.add(healPotion);
Client client = new Client();
client.printPrice(doranBlade);
client.printPrice(bag);
}
private void printPrice(Component component) {
System.out.println(component.getPrice());
}
}
먼저 가격을 반한하는 getPrice를 가진 컴포넌트 인터페이스를 생성한 후
복합객체인 Bag, 단일 객체인 Item에서 구현해줌으로써 클라이언트단에서는 동일한 방법으로
복합객체와 단일객체의 가격을 표현할 수 있습니다.