티스토리 뷰

반응형

 

☀️ 기상 모니터링 애플리케이션 만들기

현재 기상 조건(온도, 습도, 기압)을 추적해서 아래 결과를 표시하는 앱을 만들어 보려고 해요 :]

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

 

Using Key-Value Observing in Swift | Apple Developer Documentation

Notify objects about changes to the properties of other objects.

developer.apple.com

 

여기서 말하는 MyObjectToObserve는 책에서 이야기하는 Subject에요.
(이해하기 쉬운 네이밍이군요..)

책의 예시와 마찬가지로 시간을 업데이트하는 로직이 정의되어 있어요.

 

MyObserver는 당연히 옵저빙 하는 객체예요.

마찬가지로 관찰 대상(subject)을 저장하고, 그 정보를 기반으로 observation이라는 프로퍼티를 저장해요.

메서드를 보면 저장 후에 결과를 print해주는 부분이 completion handler로 정의되어 있는 것 같아요.

 

마찬가지로 아래와 같이 정의해 주고

아래와 같이 사용하면 돼요!

 

 

🎨 디자인 원칙: 상속보다는 구성(composition)을 사용한다

상속 ➡️ is-a 관계

구성 ➡️ has- a 관계

 

구성은 중복되는 로직들을 갖는 객체를 분리 구현하고, 이 객체를 주입받아 중복 로직을 호출함으로써 프로토콜을 재사용하는 방법이에요. 

상속은 중복 코드를 제거하는 좋은 방식이지만 결합도가 높아지고 유연성이 떨어지며, 다중 상속의 문제 등을 유발할 수 있어요.

그래서 중복 코드를 제거해야 할 때에는 구성을 활용하는 것이 더 좋아 보여요!

 

2장은 여기까지입니다 :]

 

정리하면, 옵저버 패턴은 관찰자와 관찰 대상을 나누어 구현하고, 1:N의 관계에서 관찰 대상에 변화가 생겼을 때 일괄적으로 관찰자에게 해당 변경을 적용하는 패턴이에요.

 

결국 책임을 분리해서 결합도를 낮추고, "변화의 trigger ➡️ 변화를 만드는 객체"의 구조라고 이해했어요.

반응형
댓글