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
- collectionview
- 스위프트
- 클린 코드
- uitableview
- SWIFT
- 리펙토링
- uiscrollview
- Human interface guide
- UICollectionView
- RxCocoa
- UITextView
- tableView
- combine
- rxswift
- 애니메이션
- Protocol
- map
- Observable
- 리펙터링
- Xcode
- HIG
- swift documentation
- 리팩토링
- Clean Code
- MVVM
- ribs
- clean architecture
- Refactoring
- ios
- swiftUI
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] 프로토콜로 리펙토링하기 본문
프로토콜로 리펙토링하는 아이디어
- 리펙토링의 핵심: 기존에 있는 코드에 영향을 최소화 하는 것
- 리펙토링 대상에 해당하는 interface들을 모두 protocol을 만들어서 선언
- 기존에 있던 리펙토링 대상의 인스턴스에 protocol을 타입을 따르고 기존 구현체를 대입
- protocol을 준수하는 새로운 구현체를 구현하여 기존것과 변경
리펙토링 전 코드 예제
ex) LogModel이라는 기능이 있고 이 모델을 2곳 이상에서 사용하고 있을때 LogModel내부 코드를 리펙토링 하고 싶은 경우?
- LogModel은 UI를 탭한 카운트를 기록하는 모델
struct LogModel {
private var countOfTap = 0
private var latestDate: Date?
mutating func addCount() {
countOfTap += 1
latestDate = .init()
}
func recordToDisk() {
let recordString = "countOfTap: \(countOfTap), latestDate: \(latestDate ?? .init())"
print("disk에 데이터 저장:", recordString)
}
}
- 이 모델을 여러곳(VC1, VC2)에서 사용하고 있는 상태
- 요구사항에 의하여 VC1에서는 deinit에서 recordToDisk()를 호출하고 VC2에서는 viewDidDisappear에서 호출
class VC1: UIViewController {
var logModel = LogModel()
@objc private func tap() {
logModel.addCount()
}
deinit {
logModel.recordToDisk()
}
}
class VC2: UIViewController {
var logModel = LogModel()
@objc private func tap() {
logModel.addCount()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
logModel.recordToDisk()
}
}
리펙토링 수행
- 1) LogModelV2라는 것을 만들어서 구현할 예정인데, LogModelV2가 LogModel과 인터페이스가 같도록 먼저 만들게하여 빌드 실패가 여러곳에서 나는것을 막고 수정범위를 좁히기 위해 프로토콜 정의
- LogModel의 인터페이스는 addCount()와 recordToDisk()이므로 두 함수만 프로토콜로 정의
protocol LogModelable {
mutating func addCount()
func recordToDisk()
}
- 2) 기존 모델에 이 프로토콜을 준수하게만들고, 사용하는쪽에 타입을 LogModelable로 수정
struct LogModel: LogModelable {
...
}
class VC1: UIViewController {
var logModel: LogModelable = LogModel() // <-
@objc private func tap() {
logModel.addCount()
}
deinit {
logModel.recordToDisk()
}
}
class VC2: UIViewController {
var logModel: LogModelable = LogModel() // <-
@objc private func tap() {
logModel.addCount()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
logModel.recordToDisk()
}
}
- 3) 이제 logModel 인스턴스에 LogModelable 프로토콜만 준수하는 어떤 구현체던지 교체가 손쉽게 가능하므로 새로 리펙토링할 LogModelV2구현
struct LogModelV2: LogModelable {
private var countOfTap = 0
private var latestDate: Date?
mutating func addCount() {
print("new!")
// ...
}
func recordToDisk() {
print("new!")
// ...
}
}
- 4) 기존 logModel 인스턴스에 LogModelV2로 교체
class VC1: UIViewController {
var logModel: LogModelable = LogModelV2() // <-
@objc private func tap() {
logModel.addCount()
}
deinit {
logModel.recordToDisk()
}
}
class VC2: UIViewController {
var logModel: LogModelable = LogModelV2() // <-
@objc private func tap() {
logModel.addCount()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
logModel.recordToDisk()
}
}
- 리펙토링 전에 있던 LogModel을 삭제하고, LogModelV2의 이름을 V2를 제외한 이름으로 replace치면 리펙토링 완료
// 삭제
//struct LogModel: LogModelable {
// private var countOfTap = 0
// private var latestDate: Date?
//
// mutating func addCount() {
// countOfTap += 1
// latestDate = .init()
// }
//
// func recordToDisk() {
// let recordString = "countOfTap: \(countOfTap), latestDate: \(latestDate ?? .init())"
// print("disk에 데이터 저장:", recordString)
// }
//}
// 리펙토링 완료된 모델 (이름 변경: LogModelV2 -> LogModel)
struct LogModel: LogModelable {
private var countOfTap = 0
private var latestDate: Date?
mutating func addCount() {
print("new!")
// ...
}
func recordToDisk() {
print("new!")
// ...
}
}
* 전체 코드: https://github.com/JK0369/ExRefactoringUsingProtocol
'Refactoring (리펙토링)' 카테고리의 다른 글
[iOS - swift] extension을 활용한 네임스페이스 리펙토링 방법 (0) | 2024.01.20 |
---|---|
[iOS - swift] enum에 공통 변수가 필요한 경우 리펙토링 방법 (wrapping) (0) | 2024.01.11 |
[iOS - swift] 예외처리로 리펙토링하기 (throw, try, catch) (2) | 2023.12.17 |
[iOS - swift] 튜플을 활용한 리펙터링 (tuple refactoring, 튜플 리턴) (2) | 2023.11.29 |
[Refactoring] 메서드와 함수의 파라미터 리펙토링 (0) | 2023.11.19 |
Comments