티스토리 뷰
☀️ 기상 모니터링 애플리케이션 만들기
현재 기상 조건(온도, 습도, 기압)을 추적해서 아래 결과를 표시하는 앱을 만들어 보려고 해요 :]
1. 현재 조건
2. 기상 통계
3. 간단한 기상 예보
기상 모니터링이므로 당연히 이 항목들은 모두 실시간으로 갱신돼야 해요.
여기에 더해 추가 요구 사항이 있어요..
다른 개발자가 직접 날씨 디스플레이를 만들어서 바로 넣을 수 있도록 확장 가능해야 합니다.
나중에 새로운 디스플레이를 손쉽게 추가할 수 있도록 해주세요.
🤖 시스템 파악하기
이 시스템은 총 3가지로 구성되어 있어요.
1. 기상 스테이션
➡️ 실제 기상 정보를 수집하는 물리 장비(데이터를 제공하는 부분)
2. 기상 스테이션으로부터 오는 정보를 추적하는 객체
➡️ WeatherData 객체
3. (제공되는 데이터를 볼 수 있는) 디스플레이 장비
➡️ 원하는 조건을 선택해서 표시 가능
쉽게 생각하면 서버에서 오는 정보를 View로 띄워주는 것처럼
기상 스테이션 ➡️ 데이터 가공 ➡️ 디스플레이 장비
의 순서로 동작이 이루어져요.
그래서 직접 구현해야하는 부분은 아래 2가지입니다.
1. Weather Data를 받아 통합하여 재가공
2. 디스플레이로 1의 결과 보여주기(옵션 선택 가능)
💽 WeatherData 클래스 살펴보기
먼저 객체를 살펴볼게요.
Swift에서는 get으로 시작하는 메서드 네이밍을 지양하지만, 책에서 Java를 베이스로 하고 있기 때문에 이름을 그대로 가져왔어요.
이제 해야 할 작업은 기상 관측값이 갱신될 때마다 호출될 메서드 measurementsChanged()를 구현하면 돼요.
🙋♂️ measurementsChanged 구현하기
이 메서드는 결국 새로 가져온 정보를 기준으로 디스플레이를 업데이트하는 작업을 해야 해요.
구현 목표를 조금 더 정리해 볼게요!
1. measurementsChanged() 메서드가 어떤 식으로 호출되는지 알 필요는 없음(호출된다는 사실만 앎)
2. measurementsChanged()에서 디스플레이를 업데이트
+ 추가될 디스플레이를 대비해 확장성 있게 만들기
이것을 바탕으로 코드를 추가해 볼게요!
이름에서 유추할 수 있듯이 각 메서드는 우리가 출력해야 될 View의 결과물들을 업데이트하는 역할을 해요.
1. 현재 조건 업데이트 ➡️ currentConditionsDisplay.update
2. 기상 통계 업데이트 ➡️ statisticsDisplay.update
3. 간단한 기상 예보 업데이트 ➡️ forecastDisplay.update
즉, 디스플레이를 갱신해요.
여기서 문제는 무엇일까요?
🥲 현재 구현 문제 이해하기
1. 화면을 update해주는 메서드들을 각 Display 객체가 가지고 있고, 이 객체들은 구체적인 구상체예요.
그래서 이 클래스는 다른 구상체에 맞춰서 코딩했기 때문에(의존) 수정이 생길 경우 이 부분에 반드시 수정이 필요해요.
➡️ 캡슐화 필요
2. 세 종류의 디스플레이가 모두 update 메서드를 가지며 같은 parameter들을 입력받고 있어요.
3. 실행 중에 디스플레이를 더하거나 빼기가 어려운 구조예요.
🔭 옵저버 패턴 사용하기
사실 iOS 개발자들은 Notification Center의 존재 때문에 Observer Pattern에 익숙한 것 같아요.
위의 구현을 옵저버 패턴을 사용해서 구현해 볼게요.
여기서 용어 정리가 필요한데,
관찰할 데이터 ➡️ Subject(주제)
이 데이터를 관찰할 관찰자 ➡️ Observer
라고 해요.
즉, 옵저버 객체들은 대상 주제를 구독하고 있으며 주제 데이터가 바뀌면 갱신 내용을 전달받아요.
(저는 주제라는 말보다는 관찰 대상이라는 말이 조금 더 와닿네요)
🧐 옵저버 패턴의 정의
옵저버 패턴은 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에게 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다(1:N) 의존성을 정의합니다.
여기서 1은 당연히 Subject, N은 Observer가 될 거예요.
1 : N의 의미는 결국 하나의 Subject를 여러 Observer들이 동시에 관찰할 수 있다는 의미예요.
옵저버 패턴에서는 주제가 상태를 저장하고 제어해요.
그래서 상태가 들어있는 객체는 하나만 있을 수 있어요.
반면에 옵저버는 상태를 사용하지만 (반드시) 소유할 필요는 없어요(관찰한 결과물을 활용하면 되니까).
그래서 옵저버는 하나의 주제에 대해 여러 개가 있을 수 있으며, 주제에서 상태가 바뀌었다는 사실을 알려 주길 기다리는 주제에 의존적인 성질을 가져요.
옵저버 패턴은 여러 방법으로 구현할 수 있는데, 보통은 주제 인터페이스와 옵저버 인터페이스가 들어있는 클래스 디자인으로 구현해요.
Subject(관찰 대상)
Observer(옵저버)
🪢 느슨한 결합(Loose Coupling)
느슨한 결합은 객체들이 상호작용할 수 있지만, 서로를 잘 모르는 관계를 의미해요.
이렇게 객체들의 관계를 느슨하게 설계하면, 유연한 구조를 만들 수 있어요.
옵저버 패턴은 느슨한 결합의 대표적인 예예요!
1. 주제는 옵저버가 특정 인터페이스(Swift에서 프로토콜)를 구현한다는 사실만 알아요
주제가 옵저버의 구상 클래스가 무엇인지, 옵저버가 무엇을 하는지 알 필요가 없어요.
2. 옵저버는 아무 때나 새로 추가하거나 제거할 수 있어요
주제는 Observer 인터페이스를 구현하는 객체의 목록에만 의존하기 때문에 이 목록을 변경함으로써 언제든지 새로운 옵저버를 추가하거나 기존 옵저버를 제거할 수 있어요.
3. 새로운 형식의 옵저버를 추가할 때도 주제를 변경할 필요가 없어요
새로운 구상 클래스가 생겼다고 해도 기존의 주제는 변경이 필요하지 않아요.
새로운 클래스에서 Observer 인터페이스(프로토콜)를 구현하고, 옵저버로 등록하기만 하면 돼요.
주제는 신경 쓸 필요가 없어요.
4. 주제와 옵저버는 서로 독립적으로 재사용할 수 있어요
5. 주제나 옵저버가 달라져도 서로에게 영향을 미치지 않아요
🎨 디자인 원칙: 상호작용하는 객체 사이에는 가능하면 느슨한 결합을 사용해야 한다.
🛠 기상 스테이션 구현하기
위에서 설명한 구조를 Observer 패턴에 맞게 다시 구성해 볼게요.
책에서는 우선 update시에 측정치를 직접 전달하는 게 상태를 갱신하는 가장 간단한 방법이라고 생각했어요.
📚 Subject 프로토콜 구현하기
📱 디스플레이 요소 구현하기
이 구현 중 update 메서드 내에서 display 하는 부분이 상당히 마음에 걸렸어요...🥲
마침 책에서도 그 이야기를 다루고, 추후 다른 챕터에서 다룬다고 이야기해요!
☁️ Weather Station 만들기
☕️ Cocoa의 Key-Value Observing을 통해 실제 옵저버 패턴 예시 보기
책에서는 이러한 옵저버 패턴의 예시 중 하나로 Cocoa를 이야기해요.
실제로는 어떻게 옵저버 패턴이 적용되는지 살펴볼게요!
https://developer.apple.com/documentation/swift/using-key-value-observing-in-swift
여기서 말하는 MyObjectToObserve는 책에서 이야기하는 Subject에요.
(이해하기 쉬운 네이밍이군요..)
책의 예시와 마찬가지로 시간을 업데이트하는 로직이 정의되어 있어요.
MyObserver는 당연히 옵저빙 하는 객체예요.
마찬가지로 관찰 대상(subject)을 저장하고, 그 정보를 기반으로 observation이라는 프로퍼티를 저장해요.
메서드를 보면 저장 후에 결과를 print해주는 부분이 completion handler로 정의되어 있는 것 같아요.
마찬가지로 아래와 같이 정의해 주고
아래와 같이 사용하면 돼요!
🎨 디자인 원칙: 상속보다는 구성(composition)을 사용한다
상속 ➡️ is-a 관계
구성 ➡️ has- a 관계
구성은 중복되는 로직들을 갖는 객체를 분리 구현하고, 이 객체를 주입받아 중복 로직을 호출함으로써 프로토콜을 재사용하는 방법이에요.
상속은 중복 코드를 제거하는 좋은 방식이지만 결합도가 높아지고 유연성이 떨어지며, 다중 상속의 문제 등을 유발할 수 있어요.
그래서 중복 코드를 제거해야 할 때에는 구성을 활용하는 것이 더 좋아 보여요!
2장은 여기까지입니다 :]
정리하면, 옵저버 패턴은 관찰자와 관찰 대상을 나누어 구현하고, 1:N의 관계에서 관찰 대상에 변화가 생겼을 때 일괄적으로 관찰자에게 해당 변경을 적용하는 패턴이에요.
결국 책임을 분리해서 결합도를 낮추고, "변화의 trigger ➡️ 변화를 만드는 객체"의 구조라고 이해했어요.
'개발 독서' 카테고리의 다른 글
[헤드퍼스트 디자인패턴 with Swift] - 1. 전략 패턴(Strategy Pattern) (4) | 2023.03.12 |
---|---|
[클린 코드] 완결 - 후기 (0) | 2021.12.18 |
[클린 코드] 12장 - 창발성 (0) | 2021.12.15 |
[클린 코드] 11장 - 시스템 (0) | 2021.12.14 |
[클린 코드] 10장 - 클래스 (0) | 2021.12.13 |
- Total
- Today
- Yesterday
- 종이자르기#분할정복#BOJ#Python
- 쿼드트리#BOJ#분할정복#Python
- 날짜 계산#BOJ#완전탐색#Python
- Swift#Tuples#Range
- Brackets#Stacks and Queues#Codility#Python
- 리모컨#완전탐색#BOJ#Python
- django#slicing
- N으로 표현#DP#Programmers#Python
- 터틀비치#리콘#xbox#controller
- 파이썬알고리즘인터뷰#4장
- NumberofDiscIntersections#Codility#Sort#Python
- 공유기 설치#BOJ#이분탐색#Python
- 순열사이클#BOJ#Python
- 반복수열#백준알고리즘#Python
- API#lazy#
- Distinct#Codility#Python
- 나무자르기#BOJ#이분탐색#Python
- 섬의개수#백준알고리즘#Python
- filter#isalnum#lower
- 병든 나이트#BOJ#탐욕법#Python
- 텀 프로젝트#백준알고리즘#Python
- 배열합치기#분할정복#BOJ#Python
- 미로 탐색#백준알고리즘#Python
- django
- Triangle#Sorting#Codility#Python
- 토마토#백준알고리즘#Python
- PassingCars#Codility#Python
- 암호코드#dp#BOJ#Python
- 랜선자르기#이분탐색#BOJ#Python
- 백준 알고리즘#BackTracking
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |