포스트

(Deep Dive) Protocols

프로토콜 → 일종의 인증서의 개념으로 생각하면 될 것 같다.

프로토콜 정의

1
2
3
protocol Myprotocol {
    //Define requirements
}

프로토콜이란?

어떤 기능에 적합한 특정 메서드, 프로퍼티 및 기타 요구 사항의 청사진을 의미한다. 프로토콜은 클래스, 구조체, 열거형에 의해 채택되며, 프로토콜에 정의 된 요구사항의 실제 구현을 제공한다.

Class, Struct, Protocol 비교

비교는 코드로 대체하겠다.

Bird라는 class가 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Bird {
    
    var isFemale = true
    
    func layEgg() {
        if isFemale {
            print ("The bird makes a new bird in a shell.")
        }
    }
    
    func fly () {
        print("The bird flaps its wings and lifts off into the sky")
    }
}

새(조류)라는 클래스는 암컷이고, 알을 낳고, 날수있는 기능(함수)를 가지고 있다.

그리고 그 조류를 상속 받은 독수리라는 클래스를 만들어 주었다.

1
2
3
4
5
6
class Eagle : Bird { // 상속을 하였다.
     
    func soar(){
        print("The eagle glides in the air using air currents.")
    }
}

독수리는 Bird가 가지고있는 기능을 모두 사용 할 수 있다.

그리고 조류를 상속받는 펭귄도 만들어보자

1
2
3
4
5
class Penguin : Bird {
    func swin() {
        print("The penguin paddles through the water.")
    }
}

펭귄도 역시 조류가 가지고 있는 기능을 모두 사용 할 수있다

그런데 상식적으로 펭귄은 날 수 없는데? fly 함수를 사용 할 수 있다.

이것은 말이 안된다.

그리고 조류 박물관을 하나 구조체로 만들어 주었다.

조류 박물관은 조류를 상속 받을 수는 없지만 매개변수로 가져 올 수는 있다.

1
2
3
4
5
struct FlyingMuseum {
    func flyingDemo(flyingObject : Bird) {
        flyingObject.fly()
    }
}

그리고 다음과 같이 작성하였다.

조류박물관이라는 구조체를 만들었고 거기에 flyingDemo라는 함수를 만들었는데 매개변수의 타입을 조류로 하였고 호출을 하면 fly를 하게끔 하였다.

이런식으로도 표현을 할 수 있다.

마지막으로 비행기도 해보자.

1
2
3
4
5
class Airplane : Bird {
    override func fly() {
        print ("The airplane uses its engine to lift off into the air.")
    }
}

비행기도 일단 조류로 넣었다(?) 근데 조류와 달리 엔진을 사용해서 하늘을 비행하니 함수를 오버라이드하여 재정의 해주었다.

이렇게 클래스와 구조체를 사용해서 조류에대해 표현을 해봤는데, 상속을 받으면 그 해당기능을 다 사용가능하다.

그런데 펭귄은 하늘을 날 수 없고, 비행기는 알을 낳지 못한다.

하지만 클래스로 표현하면 이 모든것이 가능해진다.

그렇다면, 펭귄은 조류의 클래스를 상속 받으면서 날 수는 없게하고,

비행기는 조류의 클래스를 상속 받으면서 알을 낳지 못하게 할 수는 없을까?

이때 필요한게 바로 프로토콜이다.

프로토콜을 하나 만들어 보자

날 수 있게 하기위해 Canfly로 하였다.

1
2
3
protocol CanFly {
    func fly()
}

이 때 프로토콜에는 함수의 body내역은 적지 않는다!

이런식으로 에러가 뜬다.

그리고 조류 클래스도 약간 수정을 해주자.

1
2
3
4
5
6
7
8
9
10
class Bird {
    
    var isFemale = true
    
    func layEgg() {
        if isFemale {
            print ("The bird makes a new bird in a shell.")
        }
    }
}

이제 독수리 클래스에 Canfly 프로토콜을 적용해보자!

Canfly 프로토콜을 사용했는데 fly 함수가 없어서 에러가 발생한다.

그래서 fly함수를 새로 만들어 준다!

1
2
3
4
5
6
7
8
9
10
11
12
class Eagle : Bird, CanFly {
//           -----  ------
//            상속   프로토콜
    func fly() {
        print("The bird flaps its wings and lifts off into the sky")
    }
    // 프로토콜에 fly함수가 있으므로, 반드시 fly함수가 들어가야 한다!

    func soar(){
        print("The eagle glides in the air using air currents.")
    }
}

이젠 조류의 특성을 가지면서, 날 수 있는 함수를 별도로 만들어 주었다!

그렇다면 펭귄은 어떨까?

펭귄은 그대로 두었고 다만 이제는 fly 함수를 쓸 수가 없다.

그리고 비행기로 넘어가자

1
2
3
4
5
6
7
struct Airplane : CanFly {
// class에서 struct로 변경하였다. 프로토콜은 구조체, 클래스 둘다 사용가능하다!
    func fly() {
        print ("The airplane uses its engine to lift off into the air.")
    }
}

클래스였던것을 구조체로 바꾸어 주었다.

그리고 재정의 했던것이 이제는 의미가 없으므로 override는 지워주었다.

그리고 박물관 역시 바꿔준다. 왜냐 Bird 클래스엔 더이상 fly가 없기 때문이다!

1
2
3
4
5
struct FlyingMuseum {
    func flyingDemo(flyingObject : CanFly) {
        flyingObject.fly()
    }
}

myEagle, myPlane은 Canfly 프로토콜을 가지고 있고

위에 FlyingMuseumdㅔ도 매개변수의 타입을 Canfly 프로토콜을 가진 타입으로 하였다.

펭귄으로 하면 어떻게 될까?

이렇게 Canfly가 없다고 나온다.

이제 더이상 펭귄은 날수가 없다…

이미지로 정리해보면

처음에는 이렇게 모두 날 수 있었다.

그러다보니 날수 없는 조류도 fly라는 기능을 가질 수 있었다.

하지만 프로토콜을 적용하면서

분류를 하게 된것이다.

프로토콜을 새로 비유를 하여 해보았다.

여러 프로토콜을 사용할때는 다음과 같이 사용하면된다.

1
2
3
4
5
6
7
struct Mystructure: FirstProtocol, AnotherProtocol {
    // code
}

class MyClass : SuperClass, FirstProtocol, AnotherProtocol {
    //code
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.