# Design Pattern
## 구조 패턴
- 객체가 구조를 이루는 패턴
- 둘 이상의 객체가 상호작용하며 더 큰 의미를 만들어내는 패턴
- Bridge, Decorator, Facade, Flyweight, Proxy, Composite, Adapter가 있음
## 01. Decorator
### ✅ 설명
- 기능 확장 시 서브클래싱의 대안으로 제시 가능
- 클래스는 단일 상속만 가능하며, 형제관계인 클래스의 코드가 필요한 경우 부모클래스와 동시 상속받을 수 없음
→ 각 기능도 필요한 상태에서 각 기능을 합친 기능도 필요한 경우에 Decorator Pattern 사용 가능
- 마트료시카처럼 자기자신을 자기자신으로 감쌈
→ 클래스로 추상화하기
→ class와 subclass를 쉽게 확장할 수 있다는 장점이 존재
### ⚠️ 한계점
- Swift는 POP를 통해 기능의 수평확장을 지원하고 있음
- Decorator Pattern은 랩핑 과정이 필요하기 때문에 관리에 어려움이 있으며, 랩핑때문에 메모리 소비가 생김
### 📎 예제 코드
```swift
class Calculator {
private func setUp () {
print("계산기 세팅")
}
func calculating() {
setUp()
}
}
class Plus: Calculator {
override func calculating() {
super.calculating()
print("더하기")
}
}
class Minus: Calculator {
override func calculating() {
super.calculating()
print("빼기")
}
}
class Multiply: Calculator {
override func calculating() {
super.calculating()
print("곱하기")
}
}
class Division: Calculator {
override func calculating() {
super.calculating()
print("나누기")
}
}
class PlusAndMinus: Plus {
override func calculating() {
super.calculating()
print("빼기")
}
}
let plusAndMinus = PlusAndMinus()
plusAndMinus.calculating()
// 계산기 세팅
// 더하기
// 빼기
```

```swift
class Calculator {
private func setUp () {
print("계산기 세팅")
}
func calculating() {
setUp()
}
}
class DecoratedCalculator: Calculator {
var calculator: Calculator?
init(_ calculator: Calculator? = nil) {
self.calculator = calculator
}
override func calculating() {
super.calculating()
calculator?.setUp()
calculator?.calculating()
}
}
class Plus: DecoratedCalculator {
override func calculating() {
super.calculating()
print("더하기")
}
}
class Minus: DecoratedCalculator {
override func calculating() {
super.calculating()
print("빼기")
}
}
class Multiply: DecoratedCalculator {
override func calculating() {
super.calculating()
print("곱하기")
}
}
class Division: DecoratedCalculator {
override func calculating() {
super.calculating()
print("나누기")
}
}
let plusAndMinus = Minus(Plus())
plusAndMinus.calculating()
// 계산기 세팅 - Plus
// 계산기 세팅 - Minus
// 더하기
// 빼기
```

## 02. Composite
### 📝 설명
#### Composite
> 1. 형용사 합성의
> 2. 명사 합성물
> 출처: 옥스퍼드 영한사전
> 컴포지트 패턴(Composite pattern)이란 객체들의 관계를 **트리 구조**로 구성하여 부분-전체 계층을 표현하는 패턴으로, 사용자가 단일 객체와 복합 객체 모두 동일하게 다루도록 한다. - 위키백과
#### Composite Pattern의 구성요소
- Component : 공통적으로 수행할수 있는 기능을 가진 프로토콜
- Leaf: Component 를 채택하고 있고, 하위 트리가 없는 객체
- Composite : Component 를 채택하고 있고, Component 타입의 리스트를 가진 객체로서 해당 리스트에는 Leaf 및 Composite가 들어올수 있습니다.
#### Composite Pattern이 되기 위한 조건
- `Leaf`와 `Composite`가 동일한 프로토콜을 채택하고 있어야 한다.
- 해당 프로토콜이 `func`를 가지고 있어야 한다.
- `[Component]`를 가지고 있는 타입은 메서드 내에 리스트를 순회하며 프로토콜을 준수하는 메서드를 호출하는 로직을 가지고 있어야 한다.
### 📎 예제 코드
```swift
protocol Animal {
var name: String { get set }
func makeSound()
}
struct Dog: Animal {
var name: String
func makeSound() {
print("\(name) : 왕왕!")
}
}
struct Cat: Animal {
var name: String
func makeSound() {
print("\(name) : 야옹~")
}
}
struct Chick: Animal {
var name: String
func makeSound() {
print("\(name) : 삐약삐약")
}
}
struct AnimalFarm: Animal {
var name: String
var animals: [Animal]
func makeSound() {
print("\(name)의 동물들이 내는 소리")
animals.forEach { $0.makeSound() }
}
}
let dog1 = Dog(name: "멍멍이")
let dog2 = Dog(name: "바둑이")
let dog3 = Dog(name: "흰둥이")
let cat1 = Cat(name: "야옹이")
let cat2 = Cat(name: "나비")
let cat3 = Cat(name: "식빵")
let chick1 = Chick(name: "삐약이")
let chick2 = Chick(name: "꼬꼬")
let chick3 = Chick(name: "피닉스")
let bmoFarm = AnimalFarm(name: "비모 농장", animals: [dog1, cat1, chick1])
let serenaFarm = AnimalFarm(name: "세레나 농장", animals: [dog2, cat2, chick2])
let maxFarm = AnimalFarm(name: "맥스 농장", animals: [dog3, cat3, chick3])
let farms = AnimalFarm(name: "농장 연합", animals: [bmoFarm, serenaFarm, maxFarm])
farms.makeSound()
// 농장 연합의 동물들이 내는 소리
// 비모 농장의 동물들이 내는 소리
// 멍멍이 : 왕왕!
// 야옹이 : 야옹~
// 삐약이 : 삐약삐약
// 세레나 농장의 동물들이 내는 소리
// 바둑이 : 왕왕!
// 나비 : 야옹~
// 꼬꼬 : 삐약삐약
// 맥스 농장의 동물들이 내는 소리
// 흰둥이 : 왕왕!
// 식빵 : 야옹~
// 피닉스 : 삐약삐약
```
### ✅ 장점
- 한 번의 호출로 최하단의 코드까지 실행이 가능하다.
- 실행 로직이 단순하다.
- 새로운 `Leaf`나 `Composite` 작성이 쉽다.
- 트리의 중간 객체가 수정, 삭제되어도 코드 변경에 큰 부담이 없다.
### ⚠️ 한계점
- 트리구조가 아니라면 사용할 수 없다.
- 트리가 커질수록 객체 관계가 복잡해진다.
- 실행 순서를 보장하고 싶은 경우 트리구조가 명확해야 한다.
<details>
<summary>한계점 예시 접기/펼치기</summary>
```swift
// 비모농장이 농장 연합에서 나오고 싶지만 어딘가에 적을 대고 싶은 경우
let bmoFarm = AnimalFarm(name: "비모 농장", animals: [dog1, cat1, chick1])
let serenaFarm = AnimalFarm(name: "세레나 농장", animals: [bmoFarm, dog2, cat2, chick2]) // 세레나의 동물들 중 첫번째 요소로 비모농장이 들어갔다.
let maxFarm = AnimalFarm(name: "맥스 농장", animals: [dog3, cat3, chick3])
let farms = AnimalFarm(name: "농장 연합", animals: [serenaFarm, maxFarm]) // 비모 농장은 없다.
farms.makeSound()
// 농장 연합의 동물들이 내는 소리
// 세레나 농장의 동물들이 내는 소리
// 비모 농장의 동물들이 내는 소리
// 멍멍이 : 왕왕!
// 야옹이 : 야옹~
// 삐약이 : 삐약삐약
// 바둑이 : 왕왕!
// 나비 : 야옹~
// 꼬꼬 : 삐약삐약
// 맥스 농장의 동물들이 내는 소리
// 흰둥이 : 왕왕!
// 식빵 : 야옹~
// 피닉스 : 삐약삐약
```
</details>
👉 한 번 호출로 동일한 타입의 동일한 메서드를 모두 실행시키고 싶은 경우 사용한다.
## 03. Facade
### 📝 설명
#### Facade(Façade)
> 외관, **건물의 출입구**로 이용되는 정면 외벽 부분
>
#### 소프트웨어의 다른 커다란 코드 부분에 대하여 간략화된 인터페이스를 제공해주는 디자인 패턴
- 사용하기 복잡한 기능들을 하나의 **단순화된 창구를 통해 실행**
- 앱에서 실행할 로직이나 메서드들을 간편한 인터페이스로 재정리 → Facade 인스턴스에서 한번에 모아 실행
- **클라이언트는 복잡한 시스템을 알 필요 없이 단순한 인터페이스를 이용**
- 클라이언트와 하위 시스템이 서로 긴밀하게 연결되지 않도록 함
- Additional Facade 활용 가능
- Facade가 반드시 하나만 있어야 한다는 규칙이나 제한은 없음. 시스템의 요소마다 Facade 패턴을 적용하고 다시 그 Facade를 합친 Facade를 만드는 식으로 재귀적인 적용을 할 수 있음
- Facade 타입의 위치나 위임 형식 등에 제한이 없음
- 퍼사드 타입을 만들어 적절히 기능만 모아주면 됨
### 📎 예제 코드
```swift
protocol CamperFacade {
func doProject()
}
struct Rest {
func doNothing() {
print("멍...")
}
func sleep() {
print("zzz")
}
func thinkAboutSomethingElse() {
print("oO(복권 당첨되고 싶당)")
}
}
struct Coding {
func designStructure() {
print("구상: 이렇게 만들면 되겠지")
}
func writeCode() {
print("코드 작성: 나 천재인듯")
}
func testCode() {
print("코드 테스트: 어라 이게 아닌데")
}
func fixCode() {
print("버그 픽스: 내 길이 아닌가")
}
}
struct Camper: CamperFacade {
let rest = Rest()
let coding = Coding()
let name: String
init(_ name: String) {
self.name = name
}
func doProject() {
print("===\(name) 프로젝트 시작===")
coding.designStructure()
coding.writeCode()
rest.sleep()
coding.testCode()
rest.doNothing()
coding.fixCode()
rest.thinkAboutSomethingElse()
coding.fixCode()
rest.sleep()
coding.writeCode()
print("===\(name) 프로젝트 종료===")
}
}
let camper = Camper("맥스")
camper.doProject()
// ===맥스 프로젝트 시작===
// 구상: 이렇게 만들면 되겠지
// 코드 작성: 나 천재인듯
// zzz
// 코드 테스트: 어라 이게 아닌데
// 멍...
// 버그 픽스: 내 길이 아닌가
// oO(복권 당첨되고 싶당)
// 버그 픽스: 내 길이 아닌가
// zzz
// 코드 작성: 나 천재인듯
// ===맥스 프로젝트 종료===
```
### 📍 사용 시기
- 시스템이 너무 복잡해서 간단한 인터페이스를 통해 접근방식을 제한하고 싶을 때
- 하위 시스템이 외부와 결합도가 너무 높을 때(의존성을 낮춰야 할 때)
### ✅ 장점
- 외부에서 시스템을 사용하기 쉬워짐
- 복잡한 코드를 감춰서 클라이언트가 하위 시스템 코드를 몰라도 됨
- 하위 시스템 간의 결합도가 높을 때 이를 감소시키고 한 곳으로 모을 수 있음
### ⚠️ 한계점
- 앱 개발 초기 단계 등 설계가 복잡하지 않은 경우는 사용하기가 애매함
- 퍼사드가 앱의 모든 클래스에 결합되어 퍼사드에 대한 의존도가 너무 높아질 수 있음 → 결국 의존성을 완전히 피할 수는 없다
- Facade 패턴을 사용하기 위해 새로운 계층이 추가되면 관리할 타입이 하나 더 생성됨 → 유지보수 측면에서 공수 발생
👉 추상화하고자 하는 시스템의 복잡도, 그리고 퍼사드를 통해 얻게되는 이점과 유지보수 비용을 비교하며 결정해야 함
----
### 참고링크
- [📖 위키백과 - 컴포지트 패턴](https://ko.wikipedia.org/wiki/컴포지트_패턴)
- [📖 위키백과 - 데코레이터 패턴](https://ko.wikipedia.org/wiki/데코레이터_패턴)
- [📖 위키백과 - 퍼사드 패턴](https://ko.wikipedia.org/wiki/퍼사드_패턴)
- [🐻 야곰닷넷 - Decorator](https://yagom.net/courses/design-pattern-in-swift/lessons/%ea%b5%ac%ec%a1%b0-%ed%8c%a8%ed%84%b4/topic/decorator/)
- [🐻 야곰닷넷 - Composite](https://yagom.net/courses/design-pattern-in-swift/lessons/%ea%b5%ac%ec%a1%b0-%ed%8c%a8%ed%84%b4/topic/composite/)
- [🐻 야곰닷넷 - Facade](https://yagom.net/courses/design-pattern-in-swift/lessons/구조-패턴/topic/facade/)