---
# System prepended metadata

title: neck tea

---

- 이번 활동학습은 활동학습 전 그룹별로 Design Pattern을 먼저 공부해오셔야 합니다.
- 각 전문가 모둠은 정해진 3개의 Design Pattern을 공부하고, 다른 모둠에게 설명하기위한 Keynote나 Notion 페이지, 예제코드 등을 준비합니다.
    - 하나의 패턴당 설명시간이 10분을 넘지 않게 준비합니다.
    - 모둠원이 맡은 주제를 모두 설명할 수 있을 정도로 공부합니다.
    - 다른 모둠원도 열람할 수 있도록 자료를 압축해 활동학습 게시판에 업로드합니다.
- 서로 무얼 공부하는지는 비밀로 해주세요

Iterator(반복자) 패턴
Mediator(중재자) 패턴
Memento(메멘토) 패턴

---

# neck tea

- ~란
- 언제 사용하는지? 어떤 문제를 해결하는지
- 구조
- 장점 단점
- 예제코드

```swift!
enum Event {
    case tapButton
    case textFieldAppear
}

// 컴포넌트들은 중재자 인터페이스를 사용하여 중재자와 통신한다.
// 이를 통해 컴포넌트들을 다른 중재자 객체들과 연결하여 다른 컨텍스트에서
// 해당 컴포넌트들을 사용할 수 있다.
class BaseComponent {
    fileprivate weak var mediator: Mediator?

    init(mediator: Mediator? = nil) {
        self.mediator = mediator
    }

    func update(mediator: Mediator) {
        self.mediator = mediator
    }
}

// 구상 컴포넌트들은 서로 통신하지 않는다.
// 그들은 하나의 통신 채널만 가지고 있고,
// 이 채널을 통해서 중재자에게 알림들을 보낸다.
class TextField: BaseComponent {
    func 등장() {
        print("텍스트필드 등장")
        mediator?.notify(sender: self, event: .textFieldAppear)
    }
}

class Button: BaseComponent {
    func 사용자버튼탭() {
        mediator?.notify(sender: self, event: .tapButton)
    }
    
    func 버튼비활성화() {
        print("버튼비활성화")
    }
}

// 중재자 프로토콜은 컴포넌트들에서 사용하는 메서드를 선언하여 다양한 이벤트를 중재자에게 알린다.
// 중재자는 이러한 이벤트에 반응해 실행을 다른 컴포넌트들에게 전달할 수 있다.
protocol Mediator: AnyObject {
    func notify(sender: BaseComponent, event: Event)
}

// 구상 중재자 클래스
// 개별 컴포넌트들의 참조가 중재자에 있다.
class ConcreteMediator: Mediator {
    private let button: Button
    private let textField: TextField
    
    init(button: Button, textField: TextField) {
        self.button = button
        self.textField = textField
        
        button.update(mediator: self)
        textField.update(mediator: self)
    }
    
    func notify(sender: BaseComponent, event: Event) {
        switch event {
        case .tapButton:
            textField.등장()
        case .textFieldAppear:
            button.버튼비활성화()
        }
    }
}

let button = Button()
let textField = TextField()
let mediator = ConcreteMediator(button: button, textField: textField)

button.사용자버튼탭()
```

```swift!
protocol Originator {
    func save() -> Memento
}

protocol Memento {
    func restore()
}

class Caretaker {
    private var history: [Memento] = []

    func undo() {
        let memonto = history.popLast()
        memonto?.restore()
    }

    func saveState(_ memento: Memento) {
        history.append(memento)
    }
}

class ConcreteMemento: Memento {
    private let originator: ConcreteOriginator
    private let age: Int

    init(originator: ConcreteOriginator, age: Int) {
        self.originator = originator
        self.age = age
    }

    func restore() {
        originator.setState(age: age)
        print("\(age)로 돌아감")
    }
}

class ConcreteOriginator: Originator {
    private var age: Int

    init(age: Int) {
        self.age = age
    }

    func save() -> Memento {
        return ConcreteMemento(originator: self, age: age)
    }

    func setState(age: Int) {
        self.age = age
    }
}

let originator = ConcreteOriginator(age: 10)
let caretaker = Caretaker()

caretaker.saveState(originator.save())

originator.setState(age: 20)
originator.setState(age: 30)

caretaker.undo()
```
![](https://i.imgur.com/AsJzcSt.png)

![](https://i.imgur.com/M9490y7.png)
```swift!
struct Countdown: Sequence {
    let start: Int

    func makeIterator() -> CountdownIterator {
        return CountdownIterator(self)
    }
}

struct CountdownIterator: IteratorProtocol {
    let countdown: Countdown
    var times = 0

    init(_ countdown: Countdown) {
        self.countdown = countdown
    }

    mutating func next() -> Int? {
        let nextNumber = countdown.start - times
        guard nextNumber > 0
            else { return nil }

        times += 1
        return nextNumber
    }
}
let threeToGo = Countdown(start: 3)

var iterator = threeToGo.makeIterator()
while let count = iterator.next() {
    print(count)
}

for count in threeToGo {
    print(count)
}

// Prints "3"
// Prints "2"
// Prints "1"
```

![스크린샷 2023-01-26 오전 1.32.29.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c37cd0e6-3559-4f30-bcc4-ece90acbb3de/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA_2023-01-26_%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB_1.32.29.png)

## 반복자 패턴 ~란
반복자는 컬렉션의 요소들의 기본 표현(리스트, 스택, 트리 등)을 노출하지 않고 그들을 하나씩 순회할 수 있도록 하는 행동 디자인 패턴이다.

Iterator Pattern은 list, stack, tree 등과 같은 기본적인 표현을 노출하지 않고 객체를 순차적으로 접근할 수 있는 방법을 제공하는 패턴입니다. Swift에서는 IteratorProtocol을 채택하여 for문을 사용하여 반복할 수 있는 타입을 정의하게 됩니다.

## 반복자 언제 사용하냐?
반복자 패턴은 컬렉션이 내부에 복잡한 데이터 구조가 있지만 이 구조의 복잡성을 보안이나 편의상의 이유로 클라이언트들로부터 숨기고 싶을 때 사용한다.

반복자 패턴을 사용하여 앱 전체에서 순회 코드의 중복을 줄인다.

반복자 패턴은 코드가 다른 데이터 구조들을 순회할 수 있기를 원할 때 또는 이러한 구조들의 타입을 미리 알 수 없을 때 사용한다.

컬렉션의 요소를 순회하는 코드를 객체 내부에 결합하게 되었을 때
컬렉션의 주요 책임은 효율적인 데이터 저장인데 컬렉션에 더 많은 순회 알고리즘들을 추가할수록 컬렉션의 주요 책임이 무엇인지 점점 명확해지지 않게 된다.

반복자 패턴을 이용하여 컬렉션의 순회 로직을 반복자라는 별도의 객체로 추출할 수 있다.

## 반복자 구조
Iterator
컬렉션의 요소 순회에 필요한 메서드들을 정의한다.

Concrete Iterator
컬렉션 순회를 위한 특정 알고리즘을 Iterator의 요구사항인 메서드에 맞게 구현한다.


Iterator 객체는 자체적으로 반복의 진행 상황을 추적해야합니다. 이를 통해 여러 개의 반복들이 서로 독립적으로 동일한 컬렉션을 반복할 수 있습니다.

Iterable Collection
Iterator 객체를 생성하기 위한 인터페이스를 생성합니다.

Concrete Collection
적절한 Concrete Iterator의 인스턴스를 반환하는 Iterator 생성 인터페이스를 구현합니다.
클라이언트가 요청 할 때마다 Concrete Iterator 인스턴스를 반환합니다.

## 메멘토패턴 언제 사용하는가? 어떤 문제를 해결하는가.
객체의 이전 상태를 복원할 수 있도록 객체의 상태의 스냅샷을 생성하려는 경우에 사용한다.

객체를 특정 상태로 되돌리기 위해서는 그 시점의 상태를 저장해둬야한다. 객체의 상태를 저장하기 위해서는 외부에서 객체의 필드에 직접적으로 접근해야한다. 그러나 해당 객체의 필드들의 접근제한 레벨을 낮춰야하고 그러면 해당 객체의 캡슐화가 깨지게된다.

메멘토 패턴을 이용하여 객체가 스스로 상태의 스냅샷을 만들고 다른 객체는 스냅샷에 상태에 직접적으로 접근 못하게 할 수 있다.


프로그래밍을 하다 보면 객체의 내부 상태를 기록해둬야 할 때가 있습니다. 이러한 상황에는 오류에서 복구할 수 있도록 하거나 텍스트 편집기에서 실행 취소 기능을 구현할 때 필요할 거예요. 이러한 상황에서 객체의 상태를 기록해줘야 하는데 이를 외부에 저장하거나 다른 객체에서 접근 가능하도록 하면 캡슐화를 위반하게 됩니다. 즉 상태를 저장할 클래스의 모든 내부 정보를 노출하지 않고 이러한 상태에 접근하는 것을 제한해줘야 하는데 이럴 때 메멘토 패턴을 사용할 수 있습니다.

Originator
자체적으로 현재의 state를 저장하는 Memento 객체를 생성할 수 있습니다.
State를 복원하기 위해 Memento를 사용합니다.
Memento
Originator의 state에 대한 스냅샷 역할을 하는 객체입니다.
Originator 이외 객체의 접근으로부터 보호합니다.
Memento를 immutable하게 만들고 생성자를 통해 데이터를 한 번만 전달합니다.
Care Taker
Memento 객체들을 저장하여 Originator의 동작을 추적합니다.
Memento의 내용을 조작하거나 검토하지 않습니다.

장점
캡슐화를 위반하지 않으면서 객체의 state(상태) 스냅샷을 생성하고 이를 이용하여 나중에 상태를 복구할 수 있다.
Caretaker가 Originator의 상태 기록을 유지하므로 Originator의 코드가 조금 더 단순화될 수 있다.
단점
상태를 많이 저장하려 하면 할수록 메모리가 많이 사용된다.
이 경우 오래된 memento가 삭제될 수 있도록 originator의 생명주기를 추적해야하는데 이는 자원을 소모하는 일이다.
몇몇 언어에서는 Originator만 Memento 객체에 접근할 수 있도록 만드는 것이 어렵다.

장점

캡슐화를 위반하지 않고 객체의 state 스냅샷을 생성할 수 있습니다.
Caretaker가 Originator의 State 기록을 유지하므로 Originator의 코드가 단순화됩니다.
단점

클라이언트가 Memento 객체를 너무 많이 생성하면 메모리가 많이 사용됩니다.
Caretaker는 오래된 memento 객체를 삭제 할 수 있도록 Originator의 생명 주기를 추적해야 합니다. 즉 자원을 소비해야 합니다.
몇몇 언어에서는 Originator만 Memento 객체에 접근할 수 있도록 만드는 것이 어려울 수 있습니다.







## Mediator(중재자) 패턴이란?

객체간의 혼란스러운 의존 관계들을 줄일 수 있는 행동 디자인 패턴으로 객체간의 직접 통신을 제한하고 중재자 객체를 통해서만 협력하도록 하는 패턴입니다.

여러 객체간의 통신으로 인한 복잡한 로직을 Mediator라는 객체에게 위임하여 객체간의 결합도를 낮추고 유연한 구조를 만드는 패턴입니다.

## 이건 뭔지모름
각 Component 객체는 서로를 모르고 Mediator에게 이벤트가 발생했다는 알림만을 보냅니다. 그러면 Mediator 객체가 이벤트를 수신하고 사용자가 지정한 로직을 수행하여 다른 Component 객체에게 전달을 해줄 수 있습니다.

각 Component는 독립된 객체이기 때문에 다른 곳에서도 재사용할 수 있고 해당 협력에서 Mediator 프로토콜을 준수하는 ConcreteMediator만 갈아끼워서 다른 협력을 구성할 수 있는 유연한 구조입니다.

객체들이 서로 직접적으로 상호작용했을 때 객체간의 결합도가 높아져서 변경에 취약하고, 내부에 특정 객체와 상호작용하는 로직을 구현해야하기 때문에 다른 곳에서 해당 객체를 재사용하기 힘들다. 

## 구조
1. 컴포넌트들은 어떤 비지니스 로직을 포함한 다양한 클래스들이다. 
각 컴포넌트에는 중재자에 대한 참조가 있는데, 이 중재자는 중재자 인터페이스의 타입으로 선언됩니다.
 컴포넌트는 중재자의 실제 클래스를 인식하지 못하므로 컴포넌트를 다른 중재자에 연결하여 재사용할 수 있습니다.
2. 중재자 인터페이스는 일반적으로 단일 알림 메서드만을 포함하는 컴포넌트들과의 통신 메서드들을 선언한다.
컴포넌트들은 자체 객체들을 포함하여 모든 컨텍스트를 이 메서드의 인수로 전달 수 있지만 이는 수신자 컴포넌트와 발송자 클래스 간의 결합이 발생하지 않는 방식으로만 가능하다.

3. 구체 Mediator들은 다양한 다양한 컴포넌트 간의 관계를 캡슐화한다. 구상 중재자들은 자신이 관리하는 모든 컴포넌트에 대한 참조를 유지하고 때로는 그들의 수명 주기를 관리하기도 한다.

4. 컴포넌트들은 다른 컴포넌트들을 인식하지 않아야 한다. 컴포넌트 내에서 또는 컴포넌트에 중요한 일이 발생하면, 컴포넌트는 이를 중재자에게 알려야 한다. 중재자는 알림을 받으면 발송자를 쉽게 식별할 수 있으며, 이는 응답으로 어떤 컴포넌트가 작동되어야 하는지 결정하기에 충분할 수 있다.

- Component
    - 어떤 비지니스로직을 포함하는 다양한 객체들이다.
    - Mediator에 대한 참조를 가지고있다.
    - 다른 Component는 알지 못한다.

- Mediator
    - Conponent 객체들과의 통신 메서드들을 선언한다.(일반적으로 단일 알림 메서드)

- Concrete Mediator
    - 상호 작용 결합
    - 자신이 관리하는 모든 컴포넌트에 대한 참조를 가지고있다.

장점
다양한 컴포넌트 간의 통신을 한곳으로 추출하여 코드를 이해하고 유지 관리하기 쉽게 만들 수 있다.
각 Component는 독립된 객체이기 때문에 다른 곳에서도 재사용할 수 있고 해당 협력에서 Mediator 프로토콜을 준수하는 ConcreteMediator만 갈아끼워서 다른 협력을 구성할 수 있는 유연한 구조이다.

단점
객체간의 상호작용을 전부 Mediator 객체가 수행하기 때문에 나중에는 Mediator 객체가 복잡해지고 유지보수하기 어려워질 수 있다.

![](https://i.imgur.com/DRVucGs.png)
![](https://i.imgur.com/1ByD3Dt.png)

![](https://i.imgur.com/hGRmf8P.png)


> 중재자 패턴은 소프트웨어 공학에서 어떻게 객체들의 집합이 상호작용하는지를 함축해놓은 객체를 정의한다. 이 패턴은 프로그램의 실행 행위를 변경할 수 있기 때문에 행위 패턴으로 간주한다.
중재자 패턴을 사용하면 객체 간 통신은 중재자 객체 안에 함축된다. 객체들은 더 이상 다른 객체와 서로 직접 통신하지 않으며 대신 중재자를 통해 통신한다. 이를 통해 통신 객체 간 의존성을 줄일 수 있으므로 결합도를 감소시킨다. - [위키백과](https://ko.wikipedia.org/wiki/%EC%A4%91%EC%9E%AC%EC%9E%90_%ED%8C%A8%ED%84%B4)
> 


중재자는 객체 간의 혼란스러운 의존 관계들을 줄일 수 있는 행동 디자인 패턴이다. 이 패턴은 객체 간의 직접 통신을 제한하고 중재자 객체를 통해서만 협력하도록 한다.

## 문제

프로필을 만들고 편집하기 위한 대화상자가 있다고 가정해보자

이 대화 상자는 텍스트 필드, 체크 상자, 버튼 등과 같은 다양한 컨트롤들로 구성된다.

![](https://i.imgur.com/QYOx8M0.png)

일부 요소들은 다른 요소들과 상호작용할 수 있다. 

예를 들어, “개가 있음” 체크박스를 선택하면 개의 이름을 입력하기 위한 숨겨진 텍스트 필드가 나타날 수 있다. 

또 다른 예시로 데이터를 저장하기 전에 모든 필드의 값들을 검증해야 하는 제출 버튼이 있다.

![](https://i.imgur.com/7rtDfjx.png)


이 로직을 요소들의 코드 내에서 직접 구현하면 이러한 요소들의 클래스들을 앱의 다른 양식에서 재사용하기가 훨씬 더 어려워진다. 

예를 들어, 다른 양식내에서 위에 언급한 개 관련 체크박스 클래스를 사용할 수 없다.

왜냐?

기존 클래스가 개의 이름을 입력하기 위한 텍스트 필드와 결합되어 있기 때문이다. 

이 경우 프로필 양식 렌더링과 관련된 클래스들을 전부 사용하거나 아니면 아예 사용하지 말아야 한다.

## 해결책

중재자 패턴은 서로 독립적으로 작동해야 하는 컴포넌트 간의 모든 직접 통신을 중단한 후, 대신 이러한 컴포넌트들은 호출들을 적절한 컴포넌트들로 리다이렉션하는 특수 중재자 객체를 호출하여 간접적으로 협력하라고 제안한다.

그러면 컴포넌트들은 수십 개의 동료 컴포넌트들과 결합되는 대신 단일 중재자 클래스에만 의존한다.

위 프로필 편집 양식 예시에서는 대화 상자 클래스 자체가 중재자 역할을 할 수 있다. 아마도 대화 상자 클래스는 이미 자신의 모든 하위 요소들을 인식하고 있으므로 새로운 의존관계를 도입할 필요가 없다.

![](https://i.imgur.com/CGsru3K.png)


가장 중요한 변경들은 실제 요소들에 적용된다. 제출 버튼을 살펴보면 이전에 사용자가 이 버튼을 클릭할 때마다 버튼은 모든 개별 요소들의 값들을 검증해야 했다. 이제 제출 버튼이 해야 할 유일한 일은 클릭을 대화상자에 알리는 것 하나이다. 이 알림을 받으면 대화 상자는 스스로 검증을 수행하거나 개별 요소들에게 작업을 전달한다.

따라서 버튼은 여러 개의 요소들에 연결되는 대신 대화 상자 클래스에만 의존하게된다.

→ 버튼이 사용자의 탭 액션을 받아서 다른 모든 양식의 값들을 검증하는 대신 중재자에게 이벤트를 전달해서 중재자가 각 요소들의 값을 검증하는 느낌, 이렇게 하면 버튼이 다른 요소들을 의존하지 않고 중재자만 의존하게 뎀

여기서 더 나아가 모든 타입의 대화 상자에서 공통 인터페이스를 추출하여 의존성을 더욱 느슨하게 만들 수 있다. 이 인터페이스는 모든 요소가 해당 요소들에 발생하는 일(이벤트)들을 대화 상자에 알리는 데 사용할 수 있는 알림 메서드를 선언한다. 이렇게 하면 제출 버튼은 이제 해당 인터페이스를 구현하는 모든 대화 상자들과 작업할 수 있다.

그렇게 하면, 중재자 패턴은 단일 중재자 객체 내부의 다양한 객체 간의 복잡한 관계망을 캡슐화할 수 있다. 클래스의 의존관계들이 적을수록 해당 클래스를 수정, 확장 또는 재사용하기 더 쉬워진다.

→ 인터페이스를 통해서만 소통하기 때문에 해당 인터페이스만 드러내고 다 캡슐화 시켜버리면 결합도가 떨어지는 느낌

## 실제상황 적용

![](https://i.imgur.com/y6nhOym.png)

항공기의 조종사들은 서로 직접 통신하지 않는다. 대신 항공 교통 관제사와 통신한다.

항공 교통 관제사가 없다면 조종사들은 공항 근처의 모든 비행기의 존재 여부를 인식하고 수십 명의 다른 조종사들과 우선순위를 논의해야 한다. → 비행기 충돌 횟수 증가

## 구조
![](https://i.imgur.com/soAdPi4.png)


1. 컴포넌트들은 어떤 비지니스 로직을 포함한 다양한 클래스들이다. 각 컴포넌트에는 중재자에 대한 참조가 있는데, 이 중재자는 중재자 인터페이스의 타입으로 선언된다. 컴포넌트는 중재자의 실제 클래스를 인식하지 못하므로 컴포넌트를 다른 중재자에 연결하여 다른 프로그램에서 재사용할 수 있다.
2. 중재자 인터페이스는 일반적으로 단일 알림 메서드만을 포함하는 컴포넌트들과의 통신 메서드들을 선언한다.
컴포넌트들은 자체 객체들을 포함하여 모든 컨텍스트를 이 메서드의 인수로 전달 수 있지만 이는 수신자 컴포넌트와 발송자 클래스 간의 결합이 발생하지 않는 방식으로만 가능하다.
3. 구상 중재자들은 다양한 다양한 컴포넌트 간의 관계를 캡슐화한다. 구상 중재자들은 자신이 관리하는 모든 컴포넌트에 대한 참조를 유지하고 때로는 그들의 수명 주기를 관리하기도 한다.
4. 컴포넌트들은 다른 컴포넌트들을 인식하지 않아야 한다. 컴포넌트 내에서 또는 컴포넌트에 중요한 일이 발생하면, 컴포넌트는 이를 중재자에게 알려야 한다. 중재자는 알림을 받으면 발송자를 쉽게 식별할 수 있으며, 이는 응답으로 어떤 컴포넌트가 작동되어야 하는지 결정하기에 충분할 수 있다.

컴포넌트의 관전에서는 모든 것들이 블랙박스들(기능은 알지만 작동 원리를 이해할 수 없는 복잡한 기계나 시스템)처럼 보인다. 발송자는 누가 요청을 처리할지 모르고, 수신자는 누가 처음에 요청을 보냈는지를 모른다.

→ 뭔 소린지 이해안뎀

## 의사코드

이 예시에서 중재자 패턴은 버튼들, 체크박스들, 텍스트 레이블들과 같은 다양한 UI클래스 간의 상호 의존성을 제거하는 데 도움이 된다.

![](https://i.imgur.com/2uAcg3o.png)

사용자에 의해 작동된 요소는 다른 요소들과 직접 통신하지 않는다. 대신 이 요소는 중재자에게 이 이벤트에 대해 알리고 중재자에게 해당알림과 함께 컨텍스트 정보를 전달한다.

이 예시에서는 체크 박스가 중재자의 역할을 한다. 이것은 구상 요소들이 어떻게 협력해야 하는지 알고 있으며 그들의 간접적인 의사소통을 촉진한다. 이벤트에 대한알림을 받으면 대화 상자는 이벤트를 처리헤야 하는 요소를 결정하고 그 결정에 따라 호출을 리다이렉션한다.
## 장점

단일 책임 원칙. 부피가 큰 순회 알고리즘들을 별도의 클래스들로 추출하여 클라이언트 코드와 컬렉션들을 정돈할 수 있다.

개방/폐쇄 원칙. 새로운 타입의 컬렉션들과 반복자들을 구현할 수 있으며 이들을 아무것도 훼손하지 않은 체 기존의 코드에 전달할 수 있다.

같은 컬렉션을 병렬로 순회할 수 있다. 왜냐하면 각 반복자 객체는 자신의 고유한 순회 상태가 포함되어 있기 때문이다.

같은 이유로 순회를 지연하고 필요할 때 계속할 수 있다.

## 단점

단순한 컬렉션들과만 작동하는 경우 반복자 패턴을 적용하는 것은 과도할 수 있다.

반복자를 사용하는 것은 일부 특수 컬렉션들의 요소들을 탐새갛는 것보다 덜 효율적일 수 있다.

```swift!
enum Event {
    case checkBoxSelect
    case checkBoxDeselect
}

protocol Mediator: AnyObject {
    func notify(sender: Component, event: Event)
}

class ConcreteMediator: Mediator {
    let checkBox: CheckBox
    let textField: TextField
    
    init(checkBox: CheckBox, textField: TextField) {
        self.checkBox = checkBox
        self.textField = textField
        
        self.checkBox.setUpMediator(meditor: self)
        self.textField.setUpMediator(meditor: self)
    }
    
    func notify(sender: Component, event: Event) {
        switch event {
        case .checkBoxSelect:
            textField.showTextField()
        case .checkBoxDeselect:
            textField.hideTextField()
        }
    }
}

class Component {
    weak var mediator: Mediator?
    
    func setUpMediator(meditor: Mediator) {
        self.mediator = meditor
    }
}

class CheckBox: Component {
    var isSelected: Bool = false
    
    func tapCheckBox() {
        isSelected.toggle()
        if isSelected == true {
            mediator?.notify(sender: self, event: .checkBoxSelect)
        } else {
            mediator?.notify(sender: self, event: .checkBoxDeselect)
        }
    }
}

class TextField: Component {
    var isHidden: Bool = true
    
    func showTextField() {
        isHidden = false
        print("텍스트필드 등장")
    }
    
    func hideTextField() {
        isHidden = true
        print("텍스트필드 사라짐")
    }
}


let textField = TextField()
let checkBox = CheckBox()

let mediator = ConcreteMediator(checkBox: checkBox, textField: textField)

checkBox.tapCheckBox()
checkBox.tapCheckBox()
```

## 적용

### 중재자 패턴은 일부 클래스들이 다른 클래스들과 단단하게 결합하여 변경하기 어려울 때 사용한다.

중재자 패턴을 사용하면 특정 컴포넌트에 대한 모든 변경을 나머지 컴포넌트들로부터 고립하며 클래스간의 모든 관계들을 별도의 클래스로 추출할 수 있다.

### 이 패턴은 타 컴포넌트들에 너무 의존하기 때문에 다른 프로그램에서 컴포넌트를 재사용할 수 없는 경우에 사용한다.

중재자 패턴을 적용하면, 그 후 개별 컴포넌트들은 다른 컴포넌트들을 인식하지 못한다. 또, 간접적이기는 하지만 컴포넌트들은 중재자 객체를 통해 여전히 서로 통신할 수 있다.

다른 앱에서 컴포넌트를 재사용하려면 그 앱에 새로운 중재자 클래스를 제공해야한다.

### 중재자 패턴은 몇 가지 기본 행동을 다양한 컨텍스트들에서 재사용하기 위해 수 많은 컴포넌트 자식 클래스들을 만들고 있는 스스로를 발견했을 때 사용한다.

컴포넌트들 간의 모든 관계들이 중재자 내에 포함되어 있으므로 컴포넌트들 자체를 변경할 필요 없이 새 중재자 클래스들을 도입하여 이러한 컴포넌트들이 협업할 수 있는 완전히 새로운 방법들을 쉽게 정의할 수 있다.

→ 새로운 협업을 위해 컴포넌트를 새로 만들거나, 상속하여 새로운 기능들을 구현하지 않고 중재자를 새로 만들어서 협업을 만들 수 있다.

## 구현방법

1. 더 독립적으로 만들었을 때 클래스의 유지 관리가 더 쉬워지거나 재사용이 더 간편해지는 등의 이점이 있는 단단히 결합된 클래스들을 식별한다.
2. 중재자 인터페이스를 선언하고 중재자와 다양한 컴포넌트 간의 원하는 통신 프로토콜을 선언한다. 대부분의 경우 컴포넌트들에서 알림을 수신하는 단일 메서드로 충분하다. 이 인터페이스는 다른 컨텍스트들에서 컴포넌트 클래스들을 재사용하고자 할 때 매우 중요하다. 컴포넌트가 일반 인터페이스를 통해 중재자와 함께 작동하는 한 컴포넌트를 중재자의 다른 구현과 연결할 수 있다.
3. 구상 중재자 클래스를 구현한다. 모든 컴포넌트에 대한 참조를 중재자 내부에 저장하는 것을 고려해보자. 그렇게 하면 중재자의 메서드에서 어떤 컴포넌트라도 호출할 수 있다.
4. 더 나아가 중재자가 컴포넌트 객체들의 생성 및 파괴를 담당하도록 할 수 있으며, 그러면 중재자는 팩토리 또는 퍼사드와 유사할 수 있다.
5. 컴포넌트들은 중재자 객체에 대한 참조를 저장해야한다. 이 연결은 일반적으로 컴포넌트의 생성자에서 설정되고 중재자 객체가 인수로 전달된다.
6. 다른 컴포넌트들의 메서드 대신 중재자의 알림 메서드를 호출하도록 컴포넌트의 코드를 변경한다. 그 후 다른 컴포넌트들을 호출하는 것과 관련된 코드를 중재자 클래스 안으로 추출한다. 이 코드는 중재자가 해당 컴포넌트에서 알림을 받을 때마다 실행한다.

## 장점

- 단일 책임 원칙. 다양한 컴포넌트 간의 통신을 한곳으로 추출하여 코드를 이해하고 유지 관리하기 쉽게 만들 수 있다.
- 개방/폐쇄 원칙. 실제 컴포넌트들을 변경하지 않고도 새로운 중재자들을 도입할 수 있다.
- 프로그램의 다양한 컴포넌트 간의 결합도를 줄일 수 있다.
- 개별 컴포넌트들을 더 쉽게 재사용할 수 있다.

## 단점

- 중재자가 전지전능한 객체로 발전할수도 있다.

## 장점

단일 책임 원칙. 부피가 큰 순회 알고리즘들을 별도의 클래스들로 추출하여 클라이언트 코드와 컬렉션들을 정돈할 수 있다.

개방/폐쇄 원칙. 새로운 타입의 컬렉션들과 반복자들을 구현할 수 있으며 이들을 아무것도 훼손하지 않은 체 기존의 코드에 전달할 수 있다.

같은 컬렉션을 병렬로 순회할 수 있다. 왜냐하면 각 반복자 객체는 자신의 고유한 순회 상태가 포함되어 있기 때문이다.

같은 이유로 순회를 지연하고 필요할 때 계속할 수 있다.

## 단점

단순한 컬렉션들과만 작동하는 경우 반복자 패턴을 적용하는 것은 과도할 수 있다.

반복자를 사용하는 것은 일부 특수 컬렉션들의 요소들을 탐새갛는 것보다 덜 효율적일 수 있다.

장점
Collection에 대한 정보는 Container에 은닉화해서 세부 구현을 숨길 수 있다는 장점이 있습니다. 따라서 내부는 숨긴 채로 Iterator를 통해 해당 Collection을 사용하는 인터페이스만을 공개할 수 있죠.
Collection 객체는 요소들의 관리에만 집중하고, Iterator 객체는 순회와 반복 작업에만 집중할 수 있어 단일책임원칙(SRP)을 지킬 수 있습니다.
Protocol을 통해 추상화한 내용을 고정하므로 수정에는 닫혀있고, 해당 Protocol을 채택해 확장에는 열려있죠. 다른 타입의 Collection도 별도의 코드 수정 없이 해당 Iterator를 사용할 수 있으므로 개방폐쇄원칙(OCP)을 지킬 수 있습니다.
단점
비교적 간단한 Collection에 Iterator 패턴을 적용하는 경우 과한 조치가 될 수 있다는 단점이 생길 수 있습니다.