💌 Design Pattern

[Design Pattern] Composite Pattern (컴포지트패턴) with Swift

exception_log 2022. 2. 24. 19:46

Composite Pattern 개요

Object의 Hierarchies를 표현하고 각각의 Object를 독립적으로 동일한 인터페이스를 통해 처리할 수 있게 한다.
컴포지트 패턴은 클라이언트가 복합 객체(group of object) 나 단일 객체를 동일하게 취급하는 것을 목적으로 한다. 여기서 컴포지트의 의도는 트리 구조로 작성하여, 전체-부분(whole-part) 관계를 표현하는 것이다.

 

실제 상황에서 생각해보기

  • 언제 사용하는가?
    • 복합 객체와 단일 객체의 처리 방법이 다르지 않을 경우, 전체-부분 관계로 정의할 수 있다.
    • 전체-부분 관계의 대표적인 예는 Directory-File이 존재한다.
    • 이러한 전체-부분 관계를 효율적으로 정의할 때 유용하다.

구조 예시

코드로 확인해보기

import XCTest

protocol Component {
    var parent: Component? { get set }
    func add(component: Component)
    func remove(component: Component)
    func isComposite() -> Bool
    func operation() -> String
}

extension Component {

    func add(component: Component) {}
    func remove(component: Component) {}
    func isComposite() -> Bool {
        return false
    }
}

class Leaf: Component {

    var parent: Component?

    func operation() -> String {
        return "Leaf"
    }
}

class Composite: Component {

    var parent: Component?
    
    private var children = [Component]()
    
    func add(component: Component) {
        var item = component
        item.parent = self
        children.append(item)
    }

    func remove(component: Component) {
        // ...
    }

    func isComposite() -> Bool {
        return true
    }

    func operation() -> String {
        let result = children.map({ $0.operation() })
        return "Branch(" + result.joined(separator: " ") + ")"
    }
}

class Client {

    static func someClientCode(component: Component) {
        print("Result: " + component.operation())
    }

    static func moreComplexClientCode(leftComponent: Component, rightComponent: Component) {
        if leftComponent.isComposite() {
            leftComponent.add(component: rightComponent)
        }
        print("Result: " + leftComponent.operation())
    }
}

class CompositeConceptual: XCTestCase {

    func testCompositeConceptual() {

        print("Client: I've got a simple component:")
        Client.someClientCode(component: Leaf())
        
        let tree = Composite()

        let branch1 = Composite()
        branch1.add(component: Leaf())
        branch1.add(component: Leaf())

        let branch2 = Composite()
        branch2.add(component: Leaf())
        branch2.add(component: Leaf())

        tree.add(component: branch1)
        tree.add(component: branch2)

        print("\nClient: Now I've got a composite tree:")
        Client.someClientCode(component: tree)

        print("\nClient: I don't need to check the components classes even when managing the tree:")
        Client.moreComplexClientCode(leftComponent: tree, rightComponent: Leaf())
    }
}
반응형