Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- ribs
- Observable
- uiscrollview
- 클린 코드
- 리팩토링
- 애니메이션
- SWIFT
- HIG
- clean architecture
- rxswift
- UICollectionView
- Protocol
- Refactoring
- Xcode
- MVVM
- uitableview
- 리펙터링
- Clean Code
- RxCocoa
- ios
- tableView
- Human interface guide
- 리펙토링
- 스위프트
- UITextView
- swiftUI
- swift documentation
- collectionview
- map
- combine
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[Refactoring] 10-3 API 리펙토링 (공통 모델에서 필요한 부분을 protocol을 사용하여 가져오기) 본문
Refactoring (리펙토링)
[Refactoring] 10-3 API 리펙토링 (공통 모델에서 필요한 부분을 protocol을 사용하여 가져오기)
jake-kim 2023. 7. 7. 00:32공통 모델이 있을 때 리펙토링 방법
- 보통 공통 모델에서 특정 프로퍼티만 필요한 경우, 따로 DTO를 만들어서 convert 로직을 만드는데, protocol을 활용하면 간결하게 해결이 가능
ex) 공통 모델 CommonModel이 있고, 각 모델에서 필요한 모델도 각각 있어서 convert해서 쓰는 패턴
- 공통 모델이 CommonModel처럼 있는 경우
struct CommonModel {
let age: Int
var name: String
let date: String
let visited: Bool
let imageData: Data
var message: String
}
- VC2, VC3에서 필요한 모델이 있어서 struct로 만들고 이걸 CommonModel에서 convert해서 쓰는 방식
struct Vc2Model {
let date: String
let message: String
}
extension CommonModel {
var toVc2Model: Vc2Model {
.init(date: date, message: message)
}
}
struct Vc3Model {
let age: Int
let name: String
}
extension CommonModel {
var toVc3Model: Vc3Model {
.init(age: age, name: name)
}
}
- 문제점)
- CommonModel 데이터가 있을때 각 모델에 넘겨주려면 모두 각 모델에 맞는 인스턴스를 생성해서 넘겨주어야함 (Vc2Model, Vc3Model)
프로토콜을 사용하여 리펙토링
- Vc2Model, Vc3Model 구조체를 만들필요 없이 각 VC2, VC3 에서 필요한 필드를 protocol로 만들고 이를 CommonModel에 준수도록 구현
- CommonModel에서 VC2, VC3에서 필요한 프로토콜을 준수하고 있는 상태이므로 VC2, VC3에는 그저 CommonModel 인스턴스만 넘겨주면 완료
- VC2, VC3안쪽에서도 프로토콜에 정의된 필드에만 접근할 수 있으므로 convert 로직도 필요가 없는 상태
ex) VC2, VC3에 필요한 프로토콜을 정의
- VC2에는 VC2Modelable 선언
import UIKit
protocol VC2Modelable {
var date: String { get }
var message: String { get set }
}
final class VC2: UIViewController {
private let button = UIButton()
var vc2Model: VC2Modelable?
func updateUI(model: VC2Modelable) {
button.setTitle(model.date, for: .normal)
button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
}
@objc private func didTapButton() {
vc2Model?.message = "300"
}
}
- VC3에는 VC3Modelable 선언
import UIKit
protocol VC3Modelable {
var age: Int { get }
var name: String { get set }
}
final class VC3: UIViewController {
private let button = UIButton()
var vc3Model: VC3Modelable?
func updateUI(model: VC3Modelable) {
button.setTitle("\(model.age)", for: .normal)
button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
}
@objc private func didTapButton() {
vc3Model?.name = "300"
}
}
- vc2, vc3에서 필요한 모델을 주입할땐 CommonModel 하나로 주입하면 되기 때문에 convert 로직 없이 하나의 인스턴스로 간편하게 주입이 가능한 상태
let myModel = CommonModel(
age: 1,
name: "jake",
date: "20230101",
visited: true,
imageData: Data(),
message: "message1"
)
let vc2 = VC2()
vc2.updateUI(model: myModel)
let vc3 = VC3()
vc3.updateUI(model: myModel)
정리
- API로 부터 데이터를 여러가지 필드를 한꺼번에 내려받는 경우, 몸집이 큰 struct에서 필요한 값이 있는 경우 모델을 따로 만들지 말고 필요한 곳에서 원하는 필드만 나타낸 protocol로 정의
- 몸집이 큰 structd에서 이 protocol을 따르게한 다음 이 값을 바로 주입
- protocol로 구현했을때의 장점
- 별도의 struct가 필요 없고, protocol로 정의하여 protocol만 만족하면 되는 코드가 되므로 DIP 원칙을 지키며 결합도를 느슨하게 한 형태
- struct인 별도의 모델로 만들었으면 convert하는 로직이 필요하지만 protocol로 정의하여 필요하지 않아 간결한 코드 유지보수가 가능
'Refactoring (리펙토링)' 카테고리의 다른 글
[Refactoring] 10-5 API 리펙토링 (수정된 값 반환하기) (0) | 2023.07.12 |
---|---|
[Refactoring] 10-4 API 리펙토링 (매개변수를 질의 함수로 바꾸기) (0) | 2023.07.09 |
[Refactoring] 10-2 API 리펙토링 (객체 통째로 넘기기) (0) | 2023.06.21 |
[Refactoring] 10-1 API 리펙토링 (질의 함수와 변경 함수 분리하기) (0) | 2023.06.06 |
[Refactoring] 9-6 조건부 로직 최소화 (Assertion 추가하기) (0) | 2023.06.05 |
Comments