Notice
Recent Posts
Recent Comments
Link
관리 메뉴

김종권의 iOS 앱 개발 알아가기

[Refactoring] 8-4 데이터 조작화 (참조를 값을 바꾸기) 본문

Refactoring (리펙토링)

[Refactoring] 8-4 데이터 조작화 (참조를 값을 바꾸기)

jake-kim 2023. 5. 15. 01:22

참조를 값으로 바꾸기

  • 참조 타입 vs 값 타입
    • 참조로 데이터를 다룰 땐 객체는 그대로 둔 채 그 객체의 속성만 변경
    • 값으로 데이터를 다룰 땐 새로운 속성을 담은 새로운 객체로 초기화하며 영향력은 복사된 곳에서만 고려됨
    • 참조 타입의 데이터 구조를 사용하면 이 데이터가 다른곳에 건네줄때 이 값이 마음대로 바뀔수 있음
    • 값 타입은 불변이기 때문에 불변 데이터를 같은 프로그램 외부에 건네줘도 나중에 그 값이 나 몰래 바뀌거나 내부에 영향을 주지 않는 다는 것을 확신할 수 있음

참조를 값으로 바꾸기

  • 값 타입은 불변이므로 동시성 프로그래밍분산 시스템에도 유리
    • 값을 복재해서 이곳저곳에서 사용해도 서로 간의 참조를 관리하지 않아도 되므로 유용
  • swift언어에서는 struct라는 값 타입이 있고, 보통 데이터 구조를 표현할때 struct를 사용하고 만약 이 함수 안에서 필드의 값을 변경하려면 명시적으로 mutating을 입력이 필요
    • 명시적으로 mutating을 입력하게 하는건 개발자에게 반드시 필요할때만 set하는 코드를 만들라는 의미
    • 좋은 코드는 필드를 변경하는게 아닌 새로운 생성자를 사용하여 변경하는것 (= 불변성)
  • 참조를 값 타입으로 변경하면 안되는 시점은?
    • 값 타입이 여러 곳에서 공유하고자 하는 경우
    • 항상 값타입이 좋은것은 아니고, 이에관한 내용은 다음 포스팅 글에서 값을 참조로 바꾸기에서 계속

참조를 값으로 바꾸기 예시)

  • swift에서는 기본적으로 값 타입인 struct가 있으므로 struct로 예시 작성
    • swift에서는 computed property를 사용하면 간편하게 getter, setter 함수가 역할을 대신 할 수 있으므로 함수대신 프로퍼티로 표현
struct TelephoneNumber {
    var areaCode: String
    var number: String
    
    init(areaCode: String, number: String) {
        self.areaCode = areaCode
        self.number = number
    }
}

struct Person {
    var telephoneNumber: TelephoneNumber
    
    var officeAreaCode: String {
        get { telephoneNumber.areaCode }
        set { telephoneNumber.areaCode = newValue }
    }
    
    var officeNumber: String {
        get { telephoneNumber.number }
        set { telephoneNumber.number = newValue }
    }
}
  • 문제점
    • Person에서 setter 부분에 telephoneNumber.number를 바꾸고 있는 상황
    • 필드를 바꾼다는 것은 불변성이 아니기 때문에 리펙토링 필요
  • 리펙토링
    • 1. 현재 불변성이 아닌 TelephoneNumber의 areaCode, number를 불변성으로 바꾸기
    • 2. 불변성으로 바꾸고 Person의 setter에서 필드를 바꾸는게 아닌 새로운 객체를 만들도록 수정
struct Refactor_TelephoneNumber {
    // 1. 불변성 프로퍼티로 변경 (var -> let)
    let areaCode: String
    let number: String
    
    init(areaCode: String, number: String) {
        self.areaCode = areaCode
        self.number = number
    }
}

struct Refactor_Person {
    var telephoneNumber: Refactor_TelephoneNumber
    
    // 2-1. setter안에 필드를 변경하는게 아닌 새로 객체를 만들도록 변경
    var officeAreaCode: String {
        get { telephoneNumber.areaCode }
        set { telephoneNumber = .init(areaCode: telephoneNumber.areaCode, number: newValue) }
    }
    
    // 2-2. setter안에 필드를 변경하는게 아닌 새로 객체를 만들도록 변경
    var officeNumber: String {
        get { telephoneNumber.number }
        set { telephoneNumber = .init(areaCode: newValue, number: telephoneNumber.number) }
    }
}

참고) 반대 리펙토링 - 값을 참조로 바꾸기

 

* 전체 코드: https://github.com/JK0369/ExRefactoring8_4

* 참고

- Refactoring (Martin Flowler)

Comments