반응형
Greensky0026
삽질러의 대환장 공사판
Greensky0026
전체 방문자
오늘
어제
  • 분류 전체보기 (241)
    • Language (56)
      • JAVA (13)
      • Swift (38)
      • Kotlin (4)
      • Dart (0)
      • PHP (0)
      • JavaScript (1)
    • IDE & Framework (92)
      • Spring (10)
      • Android (48)
      • iOS (8)
      • NodeJS (1)
      • CodeIgniter (3)
      • Flutter (1)
      • 분류중 (18)
    • Infra (8)
    • Database (12)
    • VCS (4)
    • Debug Log (34)
      • java (7)
      • swift (3)
      • Android (9)
      • Web (7)
      • 삽질기 (7)
    • Others (19)
      • 코딩테스트 풀이 (0)
      • IT 이야기 (18)
    • 쉼터 (2)
    • 개발공부 (14)
      • Network (1)
      • 자료구조와 알고리즘 (2)
      • Code design (8)
      • ETC (1)
      • 아카이브 (1)

블로그 메뉴

    공지사항

    • 프로그래머스 코딩 테스트 관련글 비공개 처리

    인기 글

    태그

    • level1
    • 프로그래머스
    • xcode
    • ios
    • kotlin
    • 구축
    • reduce
    • 공부
    • 프로그래밍
    • 개발
    • Android
    • IT
    • JSP
    • 코딩테스트
    • Java
    • swfit
    • map
    • 타입
    • swift
    • 예제

    최근 댓글

    최근 글

    티스토리

    hELLO · Designed By 정상우.
    Greensky0026

    삽질러의 대환장 공사판

    Swift 프로토콜 지향 프로그래밍 (POP)
    Language/Swift

    Swift 프로토콜 지향 프로그래밍 (POP)

    2021. 3. 17. 16:35
    반응형

     애플은 15년에 WWDC에서 Swift는 프로토콜 지향언어라고 말했습니다.

     

     이번 글에선 프로토콜과 익스텐션의 조합으로 프로토콜 지향 프로그래밍을

    공부해 서술하도록 하겠습니다.

     

    프로토콜 초기구현

     프로토콜 초기구현이란 프로토콜의 요구사항을 익스텐션을 통해 구현하는 것 입니다.

    Extension은 기존 타입의 기능을 확장하고, 

    Protocol은 프로토콜을 정의할 때 요구사항만을 정의할 뿐 구현은 불가능합니다.

    이 두가지를 조합해, 익스텐션에서 프로토콜이 요구하는 기능을 구현해 줄 수 있습니다.

    단, 저장 프로퍼티는 익스텐션에서 구현할수 없으므로, 각 타입에서 직접 구현해야합니다.

     

    예제

    메세지를 수신받는 Receiveable 포로토콜 입니다.

    machine과 name를 통해 수신받은 기기와 수신자를 저장합니다.

    protocol Receiveable{
        var machine: String {get set}
        var name: String {get set}
        func received(data: Any, from: Sendable)
    }
    
    extension Receiveable{
        var machine: String {
            get { return self.machine }
            set { machine = newValue }
        }
        var name: String {
            get	{ return self.name }
            set { name = newValue }
        }
        func received(data: Any, from: Sendable){
            print("\(self.name)의 \(self.machine)으로 \(from.name)가 \(from.machine)으로 보낸 \(data)를 받았습니다.")
        }
    }

     

    메세지를 전송하는 Sendable 프로토콜입니다.

    Receiveable 포로톨과 마찬가지로 machine과 name를 저장하고

    send 메서드로 데이터를 전송합니다.

    isSendableInstance메소드를 이용해 매개변수로 넣은 인스턴스가

    Seneanle을 준수하는지도 확인할 수 있습니다.

    extension Sendable{
        var machine: String {
            get { return self.machine }
            set { machine = newValue }
        }
        var name: String {
            get { return self.name }
            set { name = newValue }
        }
        var from: Sendable { return self }
    		var to: Receiveable? { get }
        
        func send(data: Any) {
            guard let receiver: Receiveable = self.to else{
                print("수신자가 지정되지 않았습니다.")
                return
            }
            receiver.received(data: data, from: self.from)
        }
        
        static func isSendableInstance(_ instance: Any) -> Bool {
            if let sendableInstance: Sendable = instance as? Sendable {
                return sendableInstance.to != nil
            }
            return false
        }
    }

     

    Sendable, Receiveable를 상속받는 클래스들을 생성했습니다.

    class Message: Sendable, Receiveable {
        var machine = "phone"
        var name: String
        var to: Receiveable?
        init(myName: String){
            self.name = myName
        }
    }
    
    class Mail: Sendable, Receiveable {
        var machine = "computer"
        var name: String
        var to: Receiveable?
        init(myName: String){
            self.name = myName
        }
    }

     

     

    이제, 사용해 볼까요?

    let myPhoneMessage: Message = Message(myName: "Greensky")
    let yourPhoneMessage: Message = Message(myName: "fireGuy")
    
    myPhoneMessage.send(data: "Hello") //수신자가 지정되지 않았습니다. : to 프로퍼티 미설정
    print(Message.isSendableInstance(myPhoneMessage)) //false : to 프로퍼티가 미설정이므로, Message타입 미준수
    
    myPhoneMessage.to = yourPhoneMessage
    myPhoneMessage.send(data: "Hello") //fireGuy의 phone으로 Greensky가 phone으로 보낸 Hello를 받았습니다.
    
    let mymail: Mail = Mail(myName: "Greensky")
    let youtMail: Mail = Mail(myName: "fireGuy")
    
    mymail.to = yourPhoneMessage
    mymail.send(data: "Hello") //fireGuy의 phone으로 Greensky가 computer으로 보낸 Hello를 받았습니다.

    종합해보면, 클래스에선 저장 인스턴스 프로퍼티만 값 매핑을 했을 뿐이고

    나머지 기능은 프로토콜의 익스텐션에 구현되에 있는걸 볼 수 있습니다.

     

    만약 프로토콜의 익스텐션에서 구현한 기능을 변경해서 쓰고 싶다면

    override와 같은 별도의 표현 없이 그대로 작성하면 됩니다.

    class Mail: Sendable, Receiveable {
        var machine = "computer"
        var name: String
        var to: Receiveable?
        init(myName: String){
            self.name = myName
        }
        
        func send(data: Any){
            print ("Mail의 send 메서드는 재정의되었습니다.")
        }
    }
    
    mymail.to = yourPhoneMessage
    mymail.send(data: "Hello") //Mail의 send 메서드는 재정의되었습니다.

     

    추가로, Receiveable과 Sendable은 machine과 name저장하는 구조가 동일했었죠?

    protocol Communicable{
        var machine: String {get set}
        var name: String {get set}
    }
    
    extension Communicable {
        var machine: String {
            get    { return self.machine }
            set { machine = newValue }
        }
        var name: String {
            get    { return self.name }
            set { name = newValue }
        }
    }
    
    protocol Receiveable: Communicable{
        func received(data: Any, from: Sendable)
    }
    
    extension Receiveable{
        func received(data: Any, from: Sendable){
            print("\(self.name)의 \(self.machine)으로 \(from.name)가 \(from.machine)으로 보낸 \(data)를 받았습니다.")
        }
    }
    
    protocol Sendable: Communicable{
        var from: Sendable { get }
        var to: Receiveable? { get }
        func send(data: Any)
        static func isSendableInstance(_ instance: Any) -> Bool
    }

    프로토콜을 추가로 생성해 상속을 사용함으로써 공통된 메서드를 제거해 보았습니다.

     

     


    공부에 도움을 준 사이트

     

    전반적인 공부 가이드라인

    yagom.net/courses/swift-basic/lessons/%ed%94%84%eb%a1%9c%ed%86%a0%ec%bd%9c-%ec%a7%80%ed%96%a5-%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%98%eb%b0%8d-p-o-p/

     

    스위프트 기초 - 야곰닷넷

    스위프트는 문법표현의 다양성이 매우 높은 언어입니다. 그래서 스위프트 문법의 모든 형태를 알기는 꽤 오랜 시간이 걸립니다. 그렇지만 최소한의 핵심 문법을 통해 무리없이 스위프트 문법을

    yagom.net

    공식 스위프트 언어 가이드 번역 홈페이지

    jusung.gitbook.io/the-swift-language-guide/language-guide/21-protocols

     

    프로토콜 (Protocols)

     

    jusung.gitbook.io

     

    반응형

    'Language > Swift' 카테고리의 다른 글

    Swift 서브스크립트 (Subscripts)  (0) 2021.03.21
    Swift 제네릭 (Generic)  (0) 2021.03.19
    Swift 접근제어  (0) 2021.03.16
    Swift 고차함수  (0) 2021.03.15
    Swift 오류처리  (0) 2021.03.15
      'Language/Swift' 카테고리의 다른 글
      • Swift 서브스크립트 (Subscripts)
      • Swift 제네릭 (Generic)
      • Swift 접근제어
      • Swift 고차함수
      Greensky0026
      Greensky0026
      점이 모여 선이 된다. 내 삽질도 언젠간 거대한 지하 도시가 되겠지!

      티스토리툴바