클래스 상속의 제약을 극복하기 위해 프로토콜을 사용
A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality.
공식문서
protocol SomeProtocol { // 요구사항을 정의 (자격증의 필수 능력만 정의)
func playPiano()
}
// 구조체에서 채택
struct MyStruct: SomeProtocol { // 이제 자격증의 능력이 생긴 것임
func playPiano() {
// 구체적인 구현
}
}
// 클래스에서 채택
class MyClass: SomeProtocol { // 이제 자격증의 능력이 생긴 것임
func playPiano() {
// 구체적인 구현
}
}
// 만약에 상속이 있는 클래스에서 채택을 할 경우
// 상속하려는 클래스 Person을 먼저 선언하고 다음에 채택하려는 프로토코로을 선언한다.
class Student: Person, SomeProtocol {
func playPiano() {
}
}
class MyClass: SomeProtocol {
func playPiano() {
// protocol에서 요구한 playPiano() 메서드 동작을 직접 구현
print("피아노를 친다")
}
}
위에서 작성한 부분에 대한 예시를 들어보려고 한다.
클래스 상속을 하게되면 무조건적으로 속성과 메서드를 상속하게 된다. 그에 따라 생기는 예시를 들어본다.
class Bird {
var isFemale = true
func layEgg() {
if isFemale {
print("새가 알을 낳는다.")
}
}
func fly() {
print("새가 하늘로 날아간다.")
}
}
Bird라는 클래스를 생성하였다. 이제 이를 상속하는 클래스들을 만들어본다.
class Eagle: Bird {
// isFamale
// layEgg()
// fly()
func soar() {
print("공중으로 치솟아 난다.")
}
}
Eagle이라는 클래스는 Bird를 상속받고 있다. 그리하여 Bird에 있는 속성과 메서드를 그대로 가지고 오게된다.
class Penguin: Bird {
// isFamale
// layEgg()
// fly()
func swim() {
print("헤엄친다.")
}
}
Penguin이라는 클래스는 Bird를 상속받고 있다. 이렇게되는 경우 펭귄은 날 수 없지만 Bird라는 클래스를 상속받았기 때문에 날 수 밖에 없다.
class Penguin: Bird {
// isFamale
// layEgg()
override func fly() {
print("펭귄은 날 수 없다...")
}
func swim() {
print("헤엄친다.")
}
}
오버라이드를 통해서 상속 받은 fly()메서드를 재정의할 수 있지만, 필요하지 않은 fly()메서드를 굳이 재정의까지하면서 필요한가?라는 의문이 들게된다.
그렇다면 여기에서 fly()라는 메서드를 필요할 때만 사용하기 위해서 프로토콜을 도입해보기러한다.
protocol CanFly {
func fly()
}
CanFly라는 프로토콜을 만들고 fly() 메서드를 요구사항으로 구현한다. 단, 여기에서는 구체적으로 구현하지 않는다.
class Bird {
var isFemale = true
func layEgg() {
if isFemale {
print("새가 알을 낳는다.")
}
}
}
기존에 있던 fly() 메서드는 프로토콜로 구현하기 때문에 해당 클래스에서 제외한다.
class Eagle: Bird, CanFly {
// isFamale
// layEgg()
func fly() {
print("독수리가 하늘로 날라올라 간다.")
}
func soar() {
print("공중으로 치솟아 난다.")
}
}
class Penguin: Bird {
// isFemale
// layEgg()
func swim() {
print("물 속을 헤엄칠 수 있다.")
}
}
Eagle Class에서는 fly()라는 메서드가 필요하여 프로토콜을 채택하였지만, Penguin클래스에서는 필요하지 않기 때문에 프로토콜을 채택하지 않았다.
이를 보면 결과적으로 똑같은 Bird라는 Class를 상속받지만, fly라는 메서드는 CanFly 프로토콜을 채택하여 사용하게 설정하였다.
내가 생각하기론 프로토콜은 다음과 같다.
프로토콜은 요구사항을 정의해놓고 해당 요구사항을 사용하고 싶은 클래스나 구조체, 열거형의 경우 프로토콜을 채택하여 요구사항을 가지고 해당 기능을 자세하게 구현하는 것이다!