[Swift] 프로토콜 지향 프로그래밍(Protocol Oriented Programming)

권승용·2022년 7월 19일
0

Swift 프로그래밍

목록 보기
5/7
post-thumbnail

Swift : 세계 최초의 POP(Protocol Oriented Programming) 언어

WWDC 2015 에서 애플은 Swift가 세계 최초의 프로토콜 지향 프로그래밍 언어임을 발표했다.


프로토콜 지향 프로그래밍이란?

프로토콜 지향 프로그래밍은 Swift 2.0에서 소개된 새로운 프로그래밍 패러다임이다.

프로토콜 확장과 프로토콜 상속, 그리고 프로토콜 합성이라는 새로운 개념들을 사용하여 프로토콜의 정의를 통해 시스템을 설계한다.

이러한 패러다임은 값 타입(구조체, 열거형)을 선호하는 Swift 특성에도 알맞다.

객체 지향 패러다임 기반의 이전 언어들은 대부분 클래스의 상속을 사용해 타입에 공통된 기능을 구현한다.

반면 Swift의 타입들은 대부분 상속이 불가능한 타입인 구조체로 구현되어 있다.

이들 값 타입들은 프로토콜의 채택과 확장을 통해 공통 기능을 가질 수 있게 되었다.


프로토콜 기반 모델링 vs 클래스 기반 모델링

소프트웨어 시스템을 설계할 때, 먼저 주어진 시스템의 요구사항을 충족하는 데 필요한 요소(elements)들을 찾아내게 된다.

그 후 이러한 요소들 사이의 관계(relationship)를 모델링한다.

그 방법으로는 슈퍼클래스(superclass)를 정의한 후 상속을 통해 관계를 모델링할 수도 있고 (클래스 기반), 프로토콜을 정의한 후 프로토콜 채택을 통해 관계를 모델링할 수도 있다 (프로토콜 기반).

애플에서는 프로토콜을 사용한 모델링을 권장한다.

클래스 vs 프로토콜

  • OOP에서 클래스의 장점

    • 캡슐화(Encapsulation) : 서로 연관된 데이터와 작업을 그룹화할 수 있다.
    • 접근제어(Access Control) : 외부에서의 접근을 차단할 수 있다. 클래스 내 정보의 불변성 유지 가능하다.
    • 추상화(Abstraction) : 연관성 있는(공통성 있는) 아이디어를 표현할 수 있다.
    • 네임스페이스(Namespace) : 네임스페이스를 통해 소프트웨어가 커지면서 발생할 수 있는 충돌을 대비 가능하다.
    • 풍부한 표현력의 문법(Expressive Syntax) : we can write method calls and properties and chain them together. we can make subscripts
    • 확장성(Extensibility) : 클래스 작성자가 내가 필요한 기능을 작성하지 않았다면 내가 추가하여 사용가능하다.

    결론적으로 위와 같은 장점들은 프로그래밍에 있어서 주요한 과제인 복잡성(complexity)의 관리를 가능하게 한다.

    그러나... Swift에서는 구조체와 열거형도 일급 객체(first class citizen)이기 떄문에 위 장점들이 사용 가능하다.

일급 객체란?

일급 객체란 아래 조건을 모두 만족하는 객체이다.

  • 변수에 저장하거나 할당할 수 있다.
  • 함수의 파라미터(인자)로 전달될 수 있다.
  • 함수의 결과로서 반환될 수 있다.
  • 클래스'만'의 장점

    ⭐️ 상속!!!

  • 그러나 클래스의 단점

    • 암시적 공유 (Implicit Sharing)
      위와 같은 상황에서 A는 B에 영향을 끼치지 않고 Data를 변경할 수 없다. 이를 방지하기 위해 Data의 복사본을 만들 수 있지만, 비효율적이다.

      값 타입은 공유하지 않고 복사하기 때문에 위와 같은 일이 일어나지 않는다.

    • 클래스의 상속은 깔끔하지 못함 (class inheritance is too intrusive)

      클래스는 단 하나의 상위 클래스만 가진다. 따라서 monolithic 하다.
      만약 여러 개의 추상화를 모델링해야 한다면? 클래스로는 불가능하다.
      클래스에서는 collection과 serialized가 동시에 될 수 없다.

      또한 클래스가 단일 상속만을 지원하기 때문에, 클래스는 자신과 연관이 없거나 '있을 지도 모르는' 상위 클래스의 모든 프로퍼티와 메서드를 상속해야 하고, 쓰이지 않을 저장 속성을 초기화해야 한다.

      이를 해결하기 위해 Swift에서는 Delegate 패턴을 사용한다.

    • 타입 관계성을 상실함 (lost type relationships)

      클래스를 통해서는 그 자신의 타입과 다른 타입간의 중요한 관계를 표현할 수 없다.

    이러한 단점들을 해결하기 위해서는 더 나은 추상화 방식이 필요하다. -> 프로토콜의 등장

프로토콜을 사용한 모델링을 권장하는 이유

프로토콜의 장점

  • 값 타입과 클래스 모두 지원
  • 정적 타입 관계와 동적 디스패치(static type relationships and dynamic dispatch) 지원
  • Non - monolithic
  • 무엇을 구현해야 하는 지 명확하다.

위 장점들을 통해 프로토콜이 클래스보다 나은 추상화를 제공하기 때문에 애플에서는 클래스보다 프로토콜을 사용한 모델링을 권장한다.

Swift에서 클래스는 다중 상속을 지원하지 않기 때문에, 시스템 설계 중 다른 클래스에서의 기능이 필요한 경우가 생긴다면(상속해야 할 경우가 생긴다면) 슈퍼클래스에 관련된 기능들을 계속해서 추가하거나 슈퍼클래스를 상속하는 새로운 클래스를 만들어 관련 기능을 추가한 후, 그 클래스를 상속해야 한다.

반면 프로토콜은 상위-하위의 상속 관계보다는 설계도와 같이 작동한다. 프로토콜 모델들은 구현 타입들이 무엇을 구현해야 하는지 알려줌으로써 추상화를 이루어낸다.

앞서 말했듯이 프로토콜은 다중 상속이 가능하기 때문에, 하나의 타입으로 여러 개의 추상화를 모델링할 수 있다. 이는 상위 클래스의 기능에 의존하게 되는 클래스의 추상화보다 훨씬 나은 방법이다. 세분화된 추상화를 통해 기능의 분리와 확장, 추가가 자유로워지기 때문이다.

그러나 무조건적으로 POP가 OOP보다 나은 것은 아니다.

  • 클래스는 객체가 '무엇'인지 정의한다.
  • 프로토콜은 객체가 '무엇을 하'는지 정의한다.

클래스는 수직적이고 프로토콜은 수평적이다. 즉, 서로 다른 방식으로 실제 세계를 추상화한다.

수직적 관계가 무수히 중첩되어도 코드를 관리하기 어려워지지만, 굉장히 많은 여러 개의 작은 프로토콜들의 수평적 관계도 코드를 난잡하게 만든다.

결국 프로그래머는 주어진 문제를 어떤 방식으로 해결하는 것이 더 알맞은 것인지 고민해서 해결 방법을 적용해야 한다.

그러나 어떤 기준으로 POP와 OOP를 적용하는지에 대해서는 더 많은 공부와 경험이 필요하다.

다음 글은 구조체와 클래스 둘 중 어떤 경우에 무엇을 사용하는지에 대해 알아보겠다. (관련 링크)

참고 : https://jayb-log.tistory.com/261?category=1003462, https://www.wwdcnotes.com/notes/wwdc15/408/

profile
ios 개발자 지망생 입니다!

0개의 댓글