[TIL] Today, I learned: 객체지향 프로그래밍 in Swift

Uno·2022년 1월 23일
1

Today, I learned: 객체지향 프로그래밍 in Swift

객체지향이란?

  • 객체지향 프로그래밍

    • = Object-Oriented Programming
    • 로직을 상태와 행위로 이뤄진 객체로 만드는 것
    • 객체로 만든 것들을 조립해서 하나의 프로그램으로 만드는 패러다임

    -> 이렇게 개념을 정의해서는 무엇인지 상상하기 상당히 어렵습니다.

가정을 해봅시다. 하나의 iOS 앱을 만드는데, 로그인 / 회원가입 / 메인 홈화면 / 상품상세화면 등 다양한 화면들이 합쳐져서 하나의 프로그램을 구성하게됩니다. 이것들을 여러명에서 구현해야하는 상황이라면, 이것들을 어떤 기준으로 업무를 나누고 어떻게 업무를 합쳐야할까요?

그리고 아주 오랜 과거에는 어떤식으로 이것들을 처리해왔을까요?

이러한 문제에 대한 답으로 "객체지향 프로그래밍" 이라는 패러다임이 시작합니다.

객체지향 프로그래밍은 실제 세계에서 아이디어를 얻어 소프트웨어에 적용한 소프트웨어 구성방식입니다. 그러므로 제가 작성할 예시도 실생활 예시로 적용해보겠습니다. 여러분들이 별다방(스벅)에 갔습니다. 그러면 점원과 고객이 둘이 마주하겠죠. 둘인 이제 객체입니다. 왜냐하면, 고객은 고객의 동작을 자신이 알아서 할겁니다. 그리고 점원은 점원 동작을 알아서 할겁니다. 분명히 서로 목적과 기능이 다르죠. 그리고 가지고 있는 자원(데이터)도 다릅니다. 이제 이 둘을 소통시켜보겠습니다.

class 고객 {
  var 내돈: Int = 10000
}

class 점원 {
  var 계좌: Int = 0
}
  • 지금 상태는 각각 자신의 돈을 프로퍼티로 가지고 있습니다. 이제 커피를 구매해야겠죠.

먼저 점원이 물어봅니다.

class 점원 {
  var 계좌: Int = 0
  
  func 구매진행(고객이선택한상품: String) {
    	if 고객이선택한상품 = "아이스아메리카노" {
        if 고객과의소통.구매진행() == 4100 {
          계죄 += 4100
        }
      } else if ...(다른상품들에대한 if)...{ }
  }
  
}
  • 점원은 고객이 오면 구매진행을 할 것입니다. 그리고 고객이 선택한 상품에 따라서 구매 금액이 달라지고, 해당 금액이 맞으면 스벅에 돈을 추가할 겁니다.
  • 그런데 지금 못보던 것이 하나 있죠. 고객과의소통 이라는 객체입니다.
  • '고객과의소통' 을 통해서 점원과 고객이 소통하는 겁니다. 왜냐하면, 고객은 누가될지 모르잖아요. 그리고 점원입장에서 VIP 고객으로 등록된 분이 아닌 이상 고객이 누군지 한정해선 안됩니다. 어떤 조건도 필요없이 커피를 사실 분이면 거래를 진행해야하니까요. 그래서 "고객과의소통" 이라는 소통창구를 만들겠습니다.
protocol 고객과의소통 {
  func 구매진행() -> Int
}
  • 프로토콜을 이용해서 어떤 메시징을 수신할지 따로 정의합니다. 그리고 이 메시징을 어떻게 처리할지는 각자의 객체들이 결정합니다.
  • 마치, 고객이 4100을 내기위해서 자신의 지갑에서 돈을 꺼내든, 부모님에게 돈을 받든 친구에게 돈을 빌리든, 그 어떤 과정도 고객이 알아서하는 겁니다.
  • 점원이 이러진 않잖아요? "고객님 친구에게 돈을 빌려서 저에게 4100을 주세요" 라고요.

그러면 어떻게 고객 객체에서 이를 구현할까요?

class 고객 {
  var 내돈 = 10000
} 

extension 고객: 고객과의소통 {
  func 구매진행() -> Int {
    내돈 -= 4100 // 혹은 친구돈 혹은 부모님용돈 대출 등등 알아서 돈을 마련한다.
  	return 4100 
  }
}
  • 위 코드를 보면, 고객과의소통이라는 한정된 메시징을 수신하게되었을 때, 구현은 고객이 알아서 처리합니다.

  • 이렇게되면, 고객들은 알아서 자신이 돈을 구해서 돈을 전달해줄 수 있게됩니다.

  • 근데 아직 문제가 있습니다. 어떤점원에게 돈을 줘야할지 모릅니다. 점원도 어떤 고객에게 돈을 받아야할지 모르구요.

class 고객 {
  var 내돈 = 10000
  
  func 커피사서마실래() {
    let 특정점원 = 점원()
    점원.대상자 = self // <-- 점원과 고객을 1:1 로 이어주기위한 코드
  }
} 

extension 고객: 고객과의소통 {
  func 구매진행() -> Int {
    내돈 -= 4100 // 혹은 친구돈 혹은 부모님용돈 대출 등등 알아서 돈을 마련한다.
  	return 4100 
  }
}
  • 고객측에서 내가 고객임을 알려주는 코드입니다. 커피사서마실래 메소드가 호출되면, 그곳에서 고객과의소통의 고객이 자신임을 알려줍니다.

  • 그러면 점원측에서는 대상자에게 돈을달라고해야겠죠? 뜬금없이 이미 구매하신 분에게 돈을 달라고 하면 안되니까요.

class 점원 {
  var 계좌: Int = 0
  var 고객: 고객과의소통 // <-- 추가된 코드
  
  func 구매진행(고객이선택한상품: String) {
    	if 고객이선택한상품 = "아이스아메리카노" {
        /* 이전 코드 */
//        if 고객과의소통.구매진행() == 4100 { 
//          계죄 += 4100
//        }
        
        /* 변경된 코드 */
        if 고객.구매진행() == 4100 { 
          계좌 += 4100
        }
      }
 	}
}
  • 추가된코드를 보면, 대상자를 받고 있고, 대상자는 고객과의소통이라는 프로토콜로 엮여있습니다. 이렇게되면 고객과의소통을 메시징을 주고 받을 고객이 자신이라고 고객이 말해주면, 점원과 매칭이 되는겁니다.

  • 이제 상품도 전달해보겠습니다.

protocol 고객과의소통 {
  func 구매진행() -> Int
  func 상품전달(상품: String)
}
  • 의사소통을 해야하니까 의사소통창구에 메시지를 추가해야겠죠.
class 고객 {
  private var 소지품 = [String]()
	...
} 

extension 고객: 고객과의소통 {
  func 구매진행() -> Int { ... }
  
  func 상품전달(상품: String)  {
    소지품.append(상품)
  }
}
  • 상품을 전달받으면 고객은 자신의 소지품에 상품을 추가합니다.
  • 여기서 소지품에 private 라는 접근제한자가 키워드로 붙었습니다. 현실세계로 생각해보면 당연합니다. 왜냐하면 고객 소지품은 고객만 건들이지 점원이 건들이면 안되니까요.
  • 마지막으로 점원상품을 전달하면 끝입니다.
class 점원 {
  var 계좌: Int = 0
  var 고객: 고객과의소통 // <-- 추가된 코드
  
  func 구매진행(고객이선택한상품: String) {
    	if 고객이선택한상품 = "아이스아메리카노" {
        if 고객.구매진행() == 4100 { 
          계좌 += 4100
          고객.상품전달(상품: "아이스아메리카노")  // <-- 추가된 코드
        }
      }
 	}
}
  • 점원객체에서 고객에세 상품을 전달하는 메시지를 호출했습니다. 파라미터로 아이스아메리카노를 전달하고 있습니다.

마무리

정리하자면, 아래 순서와 같습니다.

  1. 객체를 각각 생성한다.
  2. 객체간 소통을 위해 protocol에서 어떤 메시지로 소통할지 결정한다.
  3. 메시지를 호출하는 객체는 어떤 객체에서 처리할 지 프로퍼티로 입력받고, 필요한 순간에 메시지를 구현할 객체를 호출한다.
  4. 메시지를 구현할 객체는 어떤식으로 구현할지 구현한다.
  5. 마지막으로, 두 객체간의 연결을 위해, 메시지 구현객체는 메시지 호출객체에가 자신임을 알려준다.

cf)

  • iOS 프로그래밍을 해보신 분들은 이미 느꼈겠지만, delegate pattern과 동일한 구조입니다. delegate pattern은 객체간의 소통을 정의하는 패턴이니까요.
  • 객체지향에서의 메시징의 수신부와 구현부를 나누는 것이 iOS에서 숨쉬듯 사용되는 패턴이였던 것입니다.
  • 위 코드에서는 고객을 하나의 프로토콜로 다시 정의하고, 고객이 선택한 상품을 enum을 통해 타입을 정의하면 좀 더 현실감있는 코드가 됩니다.

참고자료

profile
iOS & Flutter

1개의 댓글

comment-user-thumbnail
2023년 12월 27일

글을 잘 쓰시네요 :) 적절한 비유 귯!!bb

답글 달기