[회고] 신입 iOS 개발자가 되기까지 feat. 카카오 자세히보기

🍎 Apple/Patterns

[iOS Design Pattern] Decorator

inu 2022. 5. 18. 16:35
반응형

Design Pattern - Decorator

  • 주어진 상황 및 용도에 따라 특정 객체에 책임을 덧붙이는 패턴입니다.
  • 기능 확장이 필요한 경우 서브클래싱 대신 사용할 수 있습니다.

기본구조

https://gmlwjd9405.github.io/2018/07/09/decorator-pattern.html

  • Decorator 패턴의 기본적인 구조입니다.
  • Component : Component와 Decorator 측에서 구현할 인터페이스입니다.
  • Decorator : Component를 상속하면서, 내부적으로 Component를 보유하고 있습니다.
  • Concrete Component : Component를 구현한 구현체로, Decorate를 적용할 기본 객체입니다.
  • Concrete Decorator : Decorator를 구현할 구현체입니다.
  • 솔직히 아직까지는 단순한 상속과 뭐가 그렇게 다른건지 잘 와닿지 않습니다. 이를 Swift 코드로 작성하면서 이해해봅시다.

코드예제

protocol Component {
    func operation()
}

class ConcreteComponent: Component {
    func operation() {
        print("Basic Operation")
    }
}
  • 먼저 기본 기능을 선언해놓은 Component와 이를 구현한 ConcreteComponent입니다.
  • operation 메서드를 호출하면 "Basic Operation" 문자를 출력합니다.
protocol Decorator: Component {
    var component: Component { get set }
}

class ConcreteDecoratorA: Decorator {
    var component: Component

    init(component: Component) {
        self.component = component
    }

    func operation() {
        component.operation()
        print("A Operation")
    }
}

class ConcreteDecoratorB: Decorator {
    var component: Component

    init(component: Component) {
        self.component = component
    }

    func operation() {
        component.operation()
        print("B Operation")
    }
}

class ConcreteDecoratorC: Decorator {
    var component: Component

    init(component: Component) {
        self.component = component
    }

    func operation() {
        component.operation()
        print("C Operation")
    }
}
  • Decorator의 기능을 선언한 Decorator Protocol과 이를 구현한 ConcreteDecoratorA,B,C 입니다.
  • Decorator는 내부에 Component를 들고 있고 이를 활용할 수 있습니다.
let basic = ConcreteComponent()

let a = ConcreteDecoratorA(component: basic)
let b = ConcreteDecoratorB(component: basic)
let c = ConcreteDecoratorC(component: basic)

a.operation()
/* Basic Operation
A Operation */

b.operation()
/* Basic Operation
B Operation */

c.operation()
/* Basic Operation
C Operation */
  • 이제 이들을 Client에서 활용해봅시다.
  • 기본적인 기능을 가진 ConcreteComponent 인스턴스를 생성하고, 이를 활용해 ConcreteDecoratorA,B,C 인스턴스를 생성해봅시다.
  • 그리고 operation을 출력하면 Basic Operation과 각 Operation이 함께 출력됩니다.
  • 여기까지는 매우 당연하게 느껴지죠? Decorator의 진짜 매력은 이 다음에 나옵니다.
let ab = ConcreteDecoratorB(component: a)
let abc = ConcreteDecoratorC(component: ab)

ab.operation()
/* Basic Operation
A Operation
B Operation */

abc.operation()
/* Basic Operation
A Operation
B Operation
C Operation */
  • Decorator는 반복적으로 기능을 더할 수 있습니다.
  • 기본 ConcreteComponent에 A를 더하고 B를 더할 수 있습니다.
  • 여기서 멈추지 않고 C를 더하는 것도 가능합니다.
  • 이렇게하면 다양한 조합의 타입(ConcreteDecoratorAB, ConcreteDecoratorAC, ConcreteDecoratorBC, ...)을 각각 생성하지 않고 조합을 통해 만들 수 있을 것입니다.

정리

  • Decorator 패턴을 사용하면 객체의 기능을 동적으로 추가할 수 있겠네요. 객체의 단일책임원칙도 지킬 수 있구요.
  • 하지만 이를 겹겹히 애워싸면서 객체를 구성하다보면 결국 객체의 정체를 제대로 파악할 수 없고, 스택과 같은 형태로 기능이 쌓이기 때문에 중간에 존재하는 특정 데코레이터를 삭제하는 것이 어렵습니다.
반응형