Notice
Recent Posts
Recent Comments
Link
관리 메뉴

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

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

Refactoring (리펙토링)

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

jake-kim 2023. 5. 22. 23:46

값을 참조로 바꾸기 개념

  • 데이터를 공유해야하는 상황에서는 모델을 참조 타입으로 변경
    • 데이터를 공유해야할때, 만약 값 타입을 사용하고 있다면 그 데이터를 변경하면 그 데이터의 모든 복제본을 찾아서 빠짐없이 갱신해주는 번거로움이 존재
    • 갱신해주다가 만약 하나라도 놓치면 데이터의 일관성이 깨져버리는 현상이 발생

값을 참조로 바꾸기 도식화

  • 값을 참조로 바꾸게 되면 *엔티티(Entity) 하나당 객체도 단 하나만 존재하며, 이런 객체들을 한데 모아 놓고 클라이언트 코드(사용하는 쪽의 코드)들이 접근을 관리해주는 일종의 저장소가 필요
    • 엔터티(Entity): 식별 가능한 개체
    • ex) 고객이라는 Entity에는 이름, 나이, 주소와 같은 Attribute를 갖음

값을 참조로 바꾸기 리펙토링 해보기

ex) Order 모델 안에 Customer가 있는 상태

  • value 타입을 사용하고 있기 때문에 order1의 updateCustomerDate()를 통해 Customer의 date를 변경했을때 order2, order3에도 일일이 다 반영해야하는 상황
struct Customer {
    private let id: String
    private var date: Date = .init()
    
    init(id: String) {
        self.id = id
    }
    
    func getID() -> String {
        id
    }
    
    mutating func updateCustomerDate() {
        date = .init()
    }
}

struct Order {
    private let number: Int
    private var customer: Customer
    
    init(number: Int, customerID: String) {
        self.number = number
        self.customer = Customer(id: customerID)
    }
    
    func getCustomer() -> Customer {
        customer
    }
    
    mutating func updateCustomerDate() {
        customer.updateCustomerDate()
    }
}

let customerID = "123"
var order1 = Order(number: 0, customerID: customerID)
let order2 = Order(number: 2, customerID: customerID)
let order3 = Order(number: 4, customerID: customerID)

order1.updateCustomerDate()
  • 리펙토링
    • 1. 같은 부류에 속하는 객체들을 보관할 저장소 생성
    • 2. 참조타입으로 변경
  • 모델을 참조 타입 (class)로 변경
class RefactorCustomer {
    private let id: String
    private var date: Date = .init()
    
    init(id: String) {
        self.id = id
    }
    
    func updateCustomerDate() {
        date = .init()
    }
}
  • 프로토콜 지향 + 저장소를 만들기 위해 프로토콜 정의
protocol Repository {
    func registerCustomer(id: String)
    func findCustomer(id: String) -> RefactorCustomer?
}
  • 프로토콜을 준수하는 저장소를 구현하여 사용
class RepositoryImpl: Repository {
    typealias ID = String
    
    var customer = [ID: RefactorCustomer]()
    
    func registerCustomer(id: String) {
        customer[id] = RefactorCustomer(id: id)
    }
    
    func findCustomer(id: String) -> RefactorCustomer? {
        customer[id]
    }
}
  • 사용하는 쪽(클라이언트 코드)에서는 위 저장소를 통해서 접근하여 사용

값을 참조로 변경할 때의 주의할점

  • 같은 부류에 속하는 객체들을 모아놓기 위해서 저장소를 만들었는데, 이 저장소는 전역 저장소로 관리될 수 있기 때문에 웬만하면 DI(Dependency Injection)으로 저장소를 주입해주도록 사용할 것

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

 

* 참고

- Refactoring (Martin Flowler)

Comments