Medium - Protocol Oriented Programming in Swift

원문 - alicanbatur

Trend 파악을 Medium 기고문 요약 포스팅 - 스위프트에서의 프로토콜 기반 프로그래밍

500x400 Photo by Thought Catalog on Unsplash

안녕하세요! 이 기사에서는 진짜 프로토콜 기반 프로그래밍이 뭔지에 대해 얘기하려고 합니다. 제 친구들 중에는 프로토콜을 많이 쓰는게 프로토콜 기반 프로그래밍이라고 생각하더라구요, 하지만 그런게 아니고 Swift 2.0에서 발표한 새로운 프로그래밍 패러다임 입니다.

Protocols

프로토콜은 메소드와 프로퍼티, 그리고 특정 작업이나 함수의 일부같은 다른 요구사항에 대한 청사진입니다. 스위프트 언어의 강력한 기능인 인터페이스죠.

// An example of a protocol
protocol TableCellProtocol {
    func cellButtonTapped()
}

스위프트는 컴파일 단계에서 클래스들이 프로토콜의 요구사항을 준수하였는지 확인합니다. 따라서 이것은 개발자들이 프로그램 실행전에 문제나 코드의 버그를 찾을 수 있게해주죠. 그리고 프로토콜은 클래스보다 더 추상화를 할 수 있습니다.

“Don’t start with a class, start with a protocol”

Tell me what Protocol Oriented Programming is

앞서 언급했듯이 프로토콜이 뭔지 말씀드렸습니다. 프로토콜 기반 프로그래밍은 클래스나 구조체, enum을 프로토콜을 사용하여 꾸미는 새로운 접근법입니다. 스위프트는 다중 상속을 지원하지 않기 때문에 당신이 클래스에 여러 개의 능력을 더하고 싶을 때 문제가 발생합니다. 프로토콜 기반 프로그래밍은 클래스나 구조체, enum을 프로토콜과 쓰면 여러 개의 기능을 구현하는 것이 가능합니다.

OOP should be enough?

클래스를 이용하여 모델 추상화를 하는 것은 상속에 의존합니다. 자식 클래스는 부모클래스의 기능을 물려받을 것입니다. 자식 클래스는 부모의 클래스를 재정의 하거나 특정한 것을 추가할 수 있죠, OOP는 당신이 다른 클래스의 기능이 필요하기 전까진 완벽할 겁니다. 스위프트에는 다중 상속이 없습니다. 그러나 프로토콜이 이것을 대신할 수 있습니다. 프로토콜 모델 추상화는 어떤 타입의 구현이 될 지 묘사합니다. 이것이 OOP와 프로토콜 OP의 가장 중요한 차이점 입니다. 그리고 OOP 보다 나은 점이 두가지 있습니다.

  • 타입은 하나 이상의 프로토콜을 준수할 수 있습니다. 이것은 완벽한 유연성을 제공합니다.
  • 프로토콜은 클래스나 구조체, enum을 채택하여 더욱 확장될 수 있습니다.

Talk is cheap, show me the code!

아래의 코드는 클래스가 아닌 무기 프로토콜을 만든 것입니다.

protocol Weapon {
    var name: String { get }
    var canFire: Bool { get }
    var canCut: Bool { get }
}
// 여러분은 변수와 함수에 대한 청사진을 만들 수 있습니다. 프로토콜에 변수를 만드는 것은 이 프로토콜을 준수하는 클래스에게 그 변수를 꼭 선언 하도록 강제할 수 있습니다. 이 예제에서는 우리는 무기 프로토콜을 준수하는 개발자에게 add name, canFire, canCut 변수를 선언하도록 했습니다.

그리고 fireable, cuttalbe 2가지 타입의 무기가 있다고 가정합시다. 우리는 무기 프로토콜의 이 기능들을 우리가 원하는 무기들을 만들 때 사용할 것입니다.

protocol Fireable {
    var magazineSize: Int { get }
}
protocol Cuttable {
    var weight: Double { get }
    var steel: String { get }
}

우리는 무기 프로토콜과 기능들을 만들었습니다. 이 것들을 모두 사용해서 구조체를 만들어봅시다.

struct LongSword: Weapon, Cuttable {
    let name: String
    let steel: String
    let weight = 7.2
    let canFire = false
    let canCut = true
}
// longsword is a weapon with ability to cut.
struct AK47: Weapon, Fireable {
    let name = "AK47"
    let magazineSize = 30
    let canFire = true
    let canCut = false
}
// ak47 is also a weapon with ability to fire bullets.

위에서 보셨듯이 우리는 프로토콜을 이용해서 우리의 구조체를 장식했습니다. 프로토콜은 우리가 원하는 기능을 추가하도록 강제했습니다. 그러나 한 가지 문제가 발생했는데 우리의 구조체에서 어떤 것이 canFire 기능을 가지고 있고 어떤 것이 canCut 기능을 가지고 있는지 알 수 없습니다. 이것을 고치려면 어떻게 해야할까요? 해답은 프로토콜 확장입니다.

extension Weapon {
    var canFire: Bool { return self is Fireable }
    var canCut: Bool { return self is Cuttable }
}

그리고 AK47과 Longsword, 프로토콜에서 canFire과 canCut을 모두 제거해주세요. “return self is Firealbe”을 이용하는 것은 또 다른 인스턴스 변수를 설정하는 것으로부터 우리를 구해주고 프로토콜 확장을 통해 우리의 프로토콜을 유연하게 만들어줍니다.

그리고 이 것들을 플레이그라운드에 추가해서 어떻게 동작하는지 살펴보세요

let longclaw = LongSword(name: "Longclaw", steel: "Valyrian")
longclaw.canCut // true
longclaw.canFire // false
longclaw.name
let ak47 = AK47()
ak47.canFire  // true
ak47.canCut // false

What? Extending Protocols? Inheritance?

프로토콜은 확장가능 합니다. 예제를 살펴봅시다.

// 저는 Fireable을 이용하여 Bombable 프로토콜을 확장했습니다.
// 그리고 maxDistance 특징을 추가하고 싶었습니다.

protocol Bombable: Fireable {
    var maxDistance: Double { get }
}
/그리고 새로운 곡사포 무기를 추가했습니다.
struct Howitzer: Weapon, Bombable {
    let name = "Howitzer"
    let magazineSize = 1
    let maxDistance = 1000 // in km
}
// 이 것이 제 코드를 더 유연하게 만들어주는 것 입니다.
// 저는 Bombable에만 maxDistance를 추가하고 Fireable에는 추가하고 싶지 않습니다.

Conclusion

많은 객체지향 언어들은 제한된 모호한 확장 정의에 둘러싸여 우리를 골치아프게 합니다. 스위프트는 이 문제를 프로토콜 확장을 이용하여 프로그래머에게 컨트롤을 할 수있게 함으로써 꽤 우아하게 해결합니다.

스위프트는 제게 OOP와 프로토콜 OP와 함수형 프로그래밍을 하게 만듭니다. 제 생각엔 이것이 사람들이 스위프트를 사랑하거나 싫어하는 이유라고 생각합니다. 스위프트는 표준 코드를 작성하지 못하게 공간을 너무 많이 열어놨습니다. 그러나 반대로 저는 이런 점 때문에 스위프트를 사용하는 것에 큰 기쁨을 느낍니다.

Summary

  • 스위프트의 프로토콜 지향 프로그래밍은 클래스의 다중 상속 요구사항을 수행할 수 있다.
  • 스위프트에서는 다중 상속이 안되기 때문에 프로토콜 확장을 통해 명확한 추상화와 유연성을 높일 수 있다.
  • 프로토콜은 required를 이용하여 그것을 준수하는 개발자에게 구현내용을 강제할 수 있는 기능이 있다.
  • 이것은 개발자에게 문제와 버그를 발생하는 코드를 줄일 수 있도록 해준다.

© 2019. All rights reserved.

Powered by Hydejack v8.1.1