[구조 패턴] Chapter 8. Composite Pattern

 

컴포짓 패턴, 소개

컴포짓 디자인 패턴은 개체들을 트리 구조로 구성하여 개별 객체와 복합 객체를 동일하게 다룰 수 있게 하는 구조 패턴이다. 이 패턴을 적용하면 클라이언트 코드는 개별 객체와 복합 객체를 구분하지 않고 동일한 인터페이스 기반으로 코드를 작성할 수 있도록 한다. 단순히 추상화 시킨다고 생각하면 된다.

 

다만 컴포짓 패턴이 적용되기 위해선 두 가지 조건이 있다.

첫째로, 단일 객체와 복합 객체를 동일하게 처리해야 하는 니즈가 있을 때

둘째로, 개별 객체와 복합 객체가 트리 구조를 만족해야 한다. 다른 말로 재귀적 구조를 만족해야 한다.

 

브랫지 패턴, 적용하기

Before

Product.java
@AllArgsConstructor
public class Product {

    private String name;
    @Getter
    private int price;

}

 

Bag.java
public class Bag {
    @Getter
    private List<Product> products = new ArrayList<>();

    public void add(Product product) {
        products.add(product);
    }
}

 

Client.java
public class Client {

    public static void main(String[] args) {
        Product cap = new Product("cap", 450);
        Product mouse = new Product("mouse", 50);

        Bag bag = new Bag();
        bag.add(cap);
        bag.add(mouse);

        Client client = new Client();
        client.printPrice(cap);
        client.printPrice(mouse);
        client.printPrice(bag);
    }

    private void printPrice(Product product) {
        System.out.println(product.getPrice());
    }

    private void printPrice(Bag bag) {
        int price = bag.getProducts().stream().mapToInt(Product::getPrice).sum();

        System.out.println(price);
    }

}

Bag에 포함된 모든 상품을 순회하며 값을 계산하려면 클라이언트가 너무 많은 정보를 알아야 한다.

가령, 객체지향 관점에서 Bag의 getProducts를 호출해서 모든 상품의 가격을 더하는 로직이 클라이언트의 책임이라고 보긴 어렵다. 만약 Bag이 Bag을 참조하거나 다른 타입의 상품을 참조한다면 클라이언트 코드는 또다시 수정되어야 한다.

 

 

 

After

 Component.java
public interface Component {
    int getPrice();
}

 

 Product.java
@AllArgsConstructor
public class Product implements Component {

    private String name;
    @Getter
    private int price;

}

 

 Bag.java

구체 타입이 아닌, Component 인터페이스 기반으로 트리 구조를 형성한다.

public class Bag implements Component {

    @Getter
    private List<Component> components = new ArrayList<>();

    public void add(Component component) {
        components.add(component);
    }

    @Override
    public int getPrice() {
        return components.stream().mapToInt(Component::getPrice).sum();
    }
}

 

Client.java
public class Client {

    public static void main(String[] args) {
        Product cap = new Product("cap", 450);
        Product mouse = new Product("mouse", 50);

        Bag bag = new Bag();
        bag.add(cap);
        bag.add(mouse);

        Client client = new Client();
        client.printPrice(cap);
        client.printPrice(mouse);
        client.printPrice(bag);
    }

    private void printPrice(Component component) {
        System.out.println(component.getPrice());
    }

}

// 결과 
// 450
// 50
// 500

Component 인터페이스를 정의해서 구현체를 만들면, 클라이언트는 복합 객체인지 단일 객체인지 구분하지 않고 인터페이스 기반으로 코드를 작성할 수 있다. 

 

인프런의 백기선님의 강의 코딩으로 학습하는 GoF의 디자인 패턴을 참고해서 작성했습니다.

 

코딩으로 학습하는 GoF의 디자인 패턴 - 인프런 | 강의

디자인 패턴을 알고 있다면 스프링 뿐 아니라 여러 다양한 기술 및 프로그래밍 언어도 보다 쉽게 학습할 수 있습니다. 또한, 보다 유연하고 재사용성이 뛰어난 객체 지향 소프트웨어를 개발할

www.inflearn.com