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 |
Tags
- 애니메이션
- 스위프트
- Xcode
- 클린 코드
- combine
- MVVM
- tableView
- 리팩토링
- UICollectionView
- Refactoring
- UITextView
- swiftUI
- Human interface guide
- ribs
- SWIFT
- Clean Code
- rxswift
- 리펙토링
- 리펙터링
- map
- Protocol
- RxCocoa
- clean architecture
- uiscrollview
- uitableview
- HIG
- swift documentation
- ios
- Observable
- collectionview
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[Refactoring] 11-3 상속 리펙토링 (서브 클래스를 델리게이트로 바꾸기) 본문
서브 클래스를 델리게이트로 바꾸기
- 특정 타입에 따라 동작이 달라지는 경우, 주로 enum case로 분기하여 구현하지만 저번시간에 알아본대로(이전 글 참고) 상속 관계를 만들면 SRP를 지키면서 더욱 유지보수 하기 쉽게 코드 관리가 가능
- 공통 코드는 수퍼클래스가 책임지고, 각각의 기능은 서브클래스로 정의하여 각 하나의 역할을 담당하도록 구현하는 것
- 이처럼 서브 클래스의 장점도 많지만, 단점이 존재
- 단점1) 수퍼클래스와 서브클래스간의 결합도가 증가하여 부모를 수정하면 자식들의 기능을 헤칠 수 있음
- 단점2) 사람 객체의 동작이 나이대와 소득 수준으로 나뉜다면, 서브클래스를 부자와 서민으로 나눌 것인데 이렇게 된다면 각 서브클래스에서 하나의 인스턴스로 두 기능 모두 사용이 불가능한 상태
- 서브 클래스를 델리게이트로 만들면 해결
- Delegate는 객체 사이의 일반적인 관계이므로 상호작용이 필요한 인터페이스를 명확히 표현 가능
상속을 델리게이트로 리펙터링 필요성
- 상속의 문제점
- 수퍼클래스에서 서브클래스의 기능을 사용하고 싶은 경우 사용이 불가
ex) 예약할 수 있는 시스템 기능을 제공하는 Booking 클래스와, 프리미움을 대상으로하는 PremiumBooking이 존재
class Booking {
let showName: String
let date: Date
init(showName: String, date: Date) {
self.showName = showName
self.date = date
}
func hasTalkback() -> Bool {
// 성수기가 아닐때만 관객과 대화하는 시간을 제공
Bool.random()
}
}
class PremiumBooking: Booking {
private let extras: Double
init(showName: String, date: Date, extras: Double) {
self.extras = extras
super.init(showName: showName, date: date)
}
override func hasTalkback() -> Bool {
// 프리미엄 예약은 항상 관객과 대화하는 시간을 제공
true
}
}
- Booking 클래스로 인스턴스를 만든 상태에서, 프리미움으로 업그레이드 하여 프리미움에 있는 기능을 사용하고 싶을때 아래처럼 사용이 불가능
booking.bePremium()
- 델리게이트를 활용하면 해결이 가능
- 주의) swift에서 사용하는 Delegate 패턴과는 조금 다른 형태이며, Delegate는 일종의 task라고 이해할 것
델리게이트로 변경
- 서브 클래싱을 제거하고 델리게이트로 접근하는게 목적
- PremiumBookingDelegate라는 구조체를 만들고 이곳에서는 extras라는 PremiumBooking에만 있던 필드와 역참조를 위해 Booking 타입 선언
- 역참조: 수퍼클래스의 필드에 접근할 때 사용 (상속을 사용할 땐 이게 없어도 되지만 델리게이트 방식은 필요)
- hasTalkback() 메소드는 원래 PremiumBooking에 있던 메소드로 구현
struct PremiumBookingDelegate {
let extras: Double
let host: Booking // 역참조
init(extras: Double, hostBooking: Booking) {
self.extras = extras
self.host = hostBooking
}
func hasTalkback() -> Bool {
true
}
}
- Booking에는 위에서 선언한 델리게이트 인스턴스를 가질 수 있도록 구현
- bePremium(extras:)를 호출하면 premiumDelegate 인스턴스가 만들어지게끔 구현
class Booking {
var premiumDelegate: PremiumBookingDelegate?
...
func bePremium(extras: Double) {
self.premiumDelegate = .init(extras: extras, hostBooking: self)
}
}
- 서브 클래스에서 hasTalkBack()이 호출되면 항상 true를 리턴해줬는데, 이 임무를 delegate에서 수행하도록 구현
// Booking.swift
func hasTalkback() -> Bool {
if let premiumDelegate {
return premiumDelegate.hasTalkback()
} else {
// 성수기가 아닐때만 관객과 대화하는 시간을 제공
return Bool.random()
}
}
(완료)
// 서브 클래스가 있던 Booking을 Delegate로 표현
class Booking {
let showName: String
let date: Date
var premiumDelegate: PremiumBookingDelegate?
init(showName: String, date: Date) {
self.showName = showName
self.date = date
}
func hasTalkback() -> Bool {
if let premiumDelegate {
return premiumDelegate.hasTalkback()
} else {
// 성수기가 아닐때만 관객과 대화하는 시간을 제공
return Bool.random()
}
}
func bePremium(extras: Double) {
self.premiumDelegate = .init(extras: extras, hostBooking: self)
}
}
(사용하는쪽)
let booking = Booking(showName: showName, date: date)
booking.bePremium(extras: extraValue)
* 전체 코드: https://github.com/JK0369/ExRefactor_11_3
* 참고
- Refactoring (Martin Flowler)
'Refactoring (리펙토링)' 카테고리의 다른 글
[iOS - swift] 복잡한 조건문 리펙토링 (if, else, else if, guard 문) (2) | 2023.10.27 |
---|---|
[Refactoring] 11-4 상속 리펙토링 (Wrapper 만들기) (0) | 2023.07.28 |
[Refactoring] 11-2 상속 리펙토링 (enum case 타입 코드를 서브클래스로 바꾸기) (1) | 2023.07.25 |
[Refactoring] 11-1 상속 리펙토링 (메서드 올리기) (0) | 2023.07.15 |
[Refactoring] 10-6 API 리펙토링 (오류 코드를 예외로 바꾸기) (0) | 2023.07.13 |
Comments