[디자인 패턴] 컴포지트 패턴

Benji Android·2023년 5월 1일
0

디자인 패턴

목록 보기
7/7
post-thumbnail

정의

객체들의 관계를 트리 구조로 구성하여 부분-전체(Part-Whole) 계층을 표한하는 패턴
단일 객체와 복합 객체 모두 동일하게 다루도록 한다.


구현할 클래스 목록

Component 를 구현하여 필요한 함수를 사용하고 하나의 Leaf 로 구성할 수 있도록 Interface를 만들어 객체를 생성한다.


Component 만들기

interface Component {
    fun getWeight(): Int
    fun getItemCount(): Int
    fun getItemName(): String
}

아이템의 전체 구성요소가 될 Interface 를 만든다.

Component 인터페이스의 경우 Item에 반드시 필요한 객체의 상태를 구현하면 된다.


Leaf 만들기

class M4A1: Component {
    override fun getWeight(): Int {
        return 3800
    }

    override fun getItemCount(): Int {
        return 1
    }

    override fun getItemName(): String {
        return "M4A1"
    }
}

class Bullet_5(private val count: Int) : Component {
    override fun getWeight(): Int {
        return 5 * getItemCount()
    }

    override fun getItemCount(): Int {
        return count
    }

    override fun getItemName(): String {
        return "5.56mm"
    }
}

... (생략)

간단하게 총과 총알을 사용하는 Item Class 를 만들었다.

Component 인터페이스를 상속받아 구현하는 구현체를 작성한다.

각 아이템의 무게, 개수, 이름을 입력한 Leaf 를 만들 수 있다.


Composite 만들기

class BattlegroundBag(
    private val name: String
) : Component {
    private val _components: ArrayList<Component> = arrayListOf()

    fun addItem(component: Component) {
        _components.add(component)
    }

    fun hasItemList(): String {
        val iter = _components.iterator()
        val sb = StringBuilder()
        while (iter.hasNext()) {
            sb.append(iter.next().getItemName())
                .append(", ")
        }
        sb.delete(sb.lastIndex - 1, sb.lastIndex)
        return sb.toString()
    }

    override fun getWeight(): Int {
        return _components.sumOf { it.getWeight() }
    }

    override fun getItemCount(): Int {
        return _components.sumOf { it.getItemCount() }
    }

    override fun getItemName(): String {
        return name
    }
}

Compostite 클래스인 BattlegroundBag 의 는 Leaf 를 저장할 수 있는 _components 리스트가 있고 가방안에 있는 모든 아이템의 무게와 갯수를 출력할 수 있도록 구현하게 되었고

가방안에 있는 Item의 종류를 출력해주는 함수도 존재합니다.

이처럼 Leaf / Tree 구조를 통해 전체와 부분을 하나의 객체처럼 사용할 수 있도록 구현하게 됩니다.


Battleground play 해보기

class Battleground {

    init {
        val level3Bag  = BattlegroundBag("3레벨 가방")
        val m4 = M4A1()
        val Kar98 = Kar98()
        val bullet5 = Bullet_5(120)
        val bullet7 = Bullet_7(30)

        level3Bag.addItem(m4)
        level3Bag.addItem(Kar98)
        level3Bag.addItem(bullet5)
        level3Bag.addItem(bullet7)

        println(level3Bag.getItemName())
        println("가방의 총 무게 : " + level3Bag.getWeight() + "g")
        println("아이템 리스트 : " + level3Bag.hasItemList())
        println("총알 개수")
        println("5탄 : ${bullet5.getItemCount()}, 7탄 : ${bullet7.getItemCount()}")
    }
}

private fun main() {
    Battleground()
}


마무리

컴포짓 패턴의 경우 전체-부분 의 개념으로 객체를 접근하도록 구현하는 패턴입니다.

트리 구조로 만들어야하는 제약이 존재 하지만, 하나의 객체를 그룹 또는 각각의 객체로 사용하기 편하기 때문에 사용하게 됩니다.

장점

  • 복잡한 트리 구조를 편리하게 사용할 수 있음.
  • 다형성과 재귀를 활용할 수 있음
  • 클라이언트 코드를 변경하지 않고 새로운 타입을 추가할 수 있음

단점

  • 트리를 만들어야 하기 때문에(공통된 인터베이스를 정의) 지나치게 일반화 해야하는 경우가 생길 수 있음

참고

profile
Android 주니어 개발자

0개의 댓글