디자인패턴

컴포지트 패턴이란?

Junuuu 2024. 2. 26. 00:01

개요

프로그래밍을 하면서 컴포지트 패턴을 종종 활용하곤 했습니다.

컴포지트 패턴에 대해 조금 더 자세하게 알아보고 이해해보고자 합니다.

 

Composite 뜻

Composite는 복합, 합성이라는 의미를 가집니다.

복잡 재료라고 하면 한 가지 물질로 이루어지지 않고 단독 재료로는 얻을 수 없는 특성을 지니도록 합니다.

디자인패턴 관점에서 생각해 보면 여러 객체들을 복합적으로 구성한다고 생각할 수 있습니다.

 

해결하는 문제

https://refactoring.guru/ko/design-patterns/composite

상자에 여러가지 물체들이 있다고 생각해 보겠습니다.

이때 상자의 가격을 얻기 위해서는 각 물품들이 어떻게 가격이 구성되는지 계산하여 다 더해야 합니다.

 

현실에서는 모든 상자를 풀고 가격을 측정하면 되지만 프로그래밍적으로는 상자 안에 또 상자가 있을지 각 가격에 대해 계산이 필요하기 때문에 가격을 측정하기 어려울 수 있습니다.

 

해결방법

https://refactoring.guru/ko/design-patterns/composite

 

가격을 계산하는 공통 인터페이스를 통하여 가격의 계산은 각자의 클래스(제품 or 상자)에서 처리합니다.

최초에 객체가 가격을 물어보면 하위 객체들이 가격을 알아서 가져오게 됩니다.

 

객체의 구조

https://refactoring.guru/ko/design-patterns/composite

 

1. Component라는 인터페이스를 두게 됩니다.

구현할 때 ItemCalculator라는 이름이 될 것 같습니다.

 

2. Leaf는 해당 Component 인터페이스를 구현합니다. 

구현할 때 HammerItemCalculator, PhoneItemCalculator 등의 이름으로 구현될 것 같습니다.

 

3. Composite는 Component 인터페이스를 구현하며, 여러 Leaf를 실제로 호출하는 역할을 수행합니다.

구현할 때 ItemCalculatorComposite라는 이름이 될 것 같습니다.

 

4. Client는 Composite를 제어합니다.

 

구현해 보기 

Spring framework와 Kotlin 언어를 활용하여 컴포지트 패턴을 구현해보고자 합니다.

 

interface ItemCalculator {
    fun calculatePrice(): Long
}

ItemCalculator 인터페이스를 선언하고 가격을 가져오기 위한 메서드를 정의합니다.

Component의 역할을 수행합니다.

 

@Component
class HammerItemCalculator: ItemCalculator {
    override fun calculatePrice(): Long {
        return HAMMER_PRICE
    }
}

const val HAMMER_PRICE = 10_000L


망치의 가격을 계산하여 가져오는 Leaf입니다.

 

@Component
class PhoneItemCalculator: ItemCalculator{
    override fun calculatePrice(): Long {
        return PHONE_PRICE
    }
}

const val PHONE_PRICE = 100_000L

휴대전화의 가격을 계산하여 가져오는 Leaf입니다.

 

 

@Component
class ItemCalculatorComposite(
        private val itemCalculator: List<ItemCalculator>
): ItemCalculator {
    override fun calculatePrice(): Long {
        return itemCalculator.sumOf { it.calculatePrice() }
    }
}

Composite는 Leaf를 Children으로 가지고 있으며 실제 자식들에게 계산을 위임하고 총합만 전달합니다.

 

 

@Component
class CompositeClient(
    private val itemCalculatorComposite: ItemCalculatorComposite,
): ApplicationRunner {

    override fun run(args: ApplicationArguments) {
        val price = itemCalculatorComposite.calculatePrice()
        println("총 가격은 : $price 입니다") // 110000원 출력
    }
}

Client는 Composite를 통하여 가격을 조회할 수 있습니다.

 

 

 

참고자료

https://en.wikipedia.org/wiki/Composite_pattern

https://ko.wikipedia.org/wiki/%EB%B3%B5%ED%95%A9_%EC%9E%AC%EB%A3%8C

https://refactoring.guru/ko/design-patterns/composite