음... 프로토콜을 제대로 공부하기 전에는.. 진짜 어려웠다.. 프로토콜을 왜 하는지ㅠㅠ 왜 따로 파일을 만들며 관리를 해줘야하는지..
그런데 이젠 어느정도 감이 잡혀서 기쁘다!
왜 프로토콜을 사용하는지? 에 대한 예시를 한 번 봐보자고~
이 예시는 유데미 - 안젤라 강의에서 가져왔다!
class Bird {
var isFemale = true
func layEgg() {
if isFemale {
print("새가 알을 낳는다.")
}
}
func fly() {
print("새가 하늘로 날아간다.")
}
}
class Eagle: Bird {
// isFamale
// layEgg()
// fly()
func soar() {
print("공중으로 치솟아 난다.")
}
}
class Penguin: Bird {
// isFamale
// layEgg()
// fly() // 상속 구조에서는 펭귄이 어쩔 수 없이 날개됨 ⭐️
func swim() {
print("헤엄친다.")
}
}
// struct가 될 수도 없고(클래스로만 구현가능), 무조건 Bird를 상속해야만 함
class Airplane: Bird {
// isFamale
// layEgg() // 상속 구조에서는 비행기가 알을 낳게됨 ⭐️
override func fly() {
print("비행기가 엔진을 사용해서 날아간다")
}
}
// 플라잉 박물관을 만듦
struct FlyingMuseum {
func flyingDemo(flyingObject: Bird) {
flyingObject.fly()
}
}
let myEagle = Eagle()
myEagle.fly()
myEagle.layEgg()
myEagle.soar()
let myPenguin = Penguin()
myPenguin.layEgg()
myPenguin.swim()
myPenguin.fly() // 문제 ===> 펭귄이 날개 됨(무조건적인 멤버 상속의 단점)
let myPlane = Airplane()
myPlane.fly()
myPlane.layEgg() // 문제 ===> 비행기가 알을 낳음
let museum = FlyingMuseum() // 타입 정의 ===> 오직 Bird 클래스 밖에 안됨
museum.flyingDemo(flyingObject: myEagle)
museum.flyingDemo(flyingObject: myPenguin)
museum.flyingDemo(flyingObject: myPlane) // Bird를 상속해야만 사용 가능
상속 구조 때문에.. 팽귄이 하늘을 날고.. 비행기가 알을 낳고.. 말도 안되는 상황이 벌어진다 ㄷ ㄷ
그래서 이 걸 해결하기 위해!
우리는 프로토콜이란 걸 사용하게 된다!
// "fly()"라는 기능을 따로 분리해 내기
protocol CanFly {
func fly() // 구체적인 구현은 하지 않음 ===> 구체적인 구현은 자격증을 채택한 곳에서
}
class Bird1 {
var isFemale = true
func layEgg() {
if isFemale {
print("새가 알을 낳는다.")
}
}
}
class Eagle1: Bird1, CanFly { // "CanFly" 자격증을 채택, 또! 클래스와 프로토콜을 동시에 채택하면 클래스부터 씀!!
// isFemale
// layEgg()
func fly() {
print("독수리가 하늘로 날라올라 간다.")
}
func soar() {
print("공중으로 활공한다.")
}
}
class Penguin1: Bird1 {
// isFemale
// layEgg()
func swim() {
print("물 속을 헤엄칠 수 있다.")
}
}
// 구조체에서 채택도 가능
struct Airplane1: CanFly {
func fly() {
print("비행기가 날아간다")
}
}
// 박물관을 만듦
struct FlyingMuseum1 {
func flyingDemo(flyingObject: CanFly) { // 중요한 기능 ===> 프로토콜을 타입으로 인식
flyingObject.fly()
}
}
let myEagle1 = Eagle1()
myEagle1.fly()
myEagle1.layEgg()
myEagle1.soar()
let myPenguin1 = Penguin1()
myPenguin1.layEgg()
myPenguin1.swim()
//myPenguin1.fly() // 더이상 펭귄이 날지 않음
let myPlane1 = Airplane1()
//myPlane1.layEgg() // 더이상 비행기가 알을 낳지 않음
myPlane1.fly()
let museum1 = FlyingMuseum1()
museum1.flyingDemo(flyingObject: myEagle1)
//museum1.flyingDemo(flyingObject: myPenguin1) // 더이상 "CanFly"자격증이 없는 펭귄은 날지 못함
museum1.flyingDemo(flyingObject: myPlane1)
이렇게 효율적으로 사용할 수 있겠죠잉?
그런데, 프로토콜도 문법이 있다는 사실!
사실 프로토콜이 이해가 잘 안됐을 땐 자격증
이라고 생각하며 공부했어요.
프로토콜의 문법은
순으로 이루어 져있습니다!
정의하기 부터 확인하자면
protocol MyProtocol { // 최소한의 요구사항 나열
func doSomething() -> Int
}
딱! 이정도만 구현하면 돼요 더는 노노.
채택하기 는
class MyClass: FamilyClass, MyProtocol { // 2) 상위클래스인 FamilyClass를 먼저 선언
}
이렇게 구현하고,
구현하기 는
class MyClass: FamilyClass, MyProtocol {
// 3) (속성/메서드) 구체적인 구현
func doSomething() -> Int {
return 2
}
}
class
, struct
, enum
내부에 자세히 구현할 것을 구현하면 됩니다!
그리고 엄청 재미있는 예시를 봤음..
바로 스위치? 같은 예시인데 맛만 보자고!
protocol Togglable {
mutating func toggle() // mutating의 키워드는 메서드 내에서 속성 변경의 의미일뿐(클래스에서 사용 가능)
}
위 같은 프로토콜을 만든 후,
enum OnOffSwitch: Togglable {
case on
case off
mutating func toggle() {
switch self { // .on .off
case .off:
self = .on
case .on:
self = .off
}
}
}
var s = OnOffSwitch.off
s.toggle()
s.toggle()
class BigSwitch: Togglable {
var isOn = false
func toggle() { // mutating 키워드 필요없음 (클래스 이기 때문)
isOn = isOn ? false : true
}
}
var big = BigSwitch()
print(big.isOn)
big.toggle()
print(big.isOn)
과 같이 구현할 수 있다! 약간.. 다크모드, 라이트모드을 구현할 때 이 방법이 잘 어울리는 것 같다.
TIL 시리즈는 막연히 제가 배운 걸 기록하는 공간입니다.