본문 바로가기

DEV

[iOS/Swift] 상속(Inheritance)과 프로토콜(Protocol)

반응형

스파르타 부트캠프 프로그래밍 심화 주차 과제 마지막 문제에 상속과 프로토콜의 장단점, 차이점을 서술하는 과제가 있었다.

상속과 프로토콜에 대해서는 알고 있었지만, 둘을 비교하여 생각한 적은 없었던 것 같다.

둘의 장단점과 차이점을 알아보자.

1. 상속(Inheritance)이란?

상속은 클래스가 다른 클래스의 속성과 메서드를 물려받는 개념이다.

부모 클래스(Superclass)에서 정의된 기능을 자식 클래스(Subclass)가 재사용하거나 확장할 수 있게 해준다.

상속의 장점

  • 코드 재사용성: 부모 클래스에서 정의한 코드를 자식 클래스에서 그대로 쓸 수 있어서 중복을 줄인다.
  • 계층 구조: 객체 간의 관계를 명확하게 표현한다. 예를 들어, Animal 클래스 아래에 Dog와 Cat을 두는 식으로 직관적인 설계가 가능하다.
  • 기능 확장: 오버라이딩(Overriding)을 통해 부모 클래스의 메서드를 자식 클래스에서 커스터마이징한다.

상속의 단점

  • 강한 결합도: 부모 클래스와 자식 클래스가 밀접하게 연결되다 보니, 부모 클래스가 바뀌면 자식 클래스에도 영향을 미친다.
  • 단일 상속 제한: Swift에서는 클래스가 하나의 부모만 가질 수 있어서 유연성이 떨어진다.
  • 복잡성 증가: 상속 계층이 깊어질수록 코드가 꼬일 가능성이 커진다.

 

2. 프로토콜(Protocol)이란?

프로토콜은 특정 기능이나 동작을 정의한 설계도 같은 개념이다.

클래스, 구조체, 열거형 등이 프로토콜을 채택해서 그 기능을 구현할 수 있다.

프로토콜의 장점

  • 유연성: 상속과 달리 여러 프로토콜을 동시에 채택할 수 있어서 다중 상속의 한계를 극복한다.
  • 구조체와 열거형 지원: 클래스(참조 타입)뿐만 아니라 값 타입(Value Type)에도 적용 가능하다.
  • 약한 결합도: 프로토콜은 구현을 강제하지 않으므로 의존성을 줄이고 모듈화에 유리하다.

프로토콜의 단점

  • 기본 구현 불가: 프로토콜 자체로는 기본 코드를 제공하지 않으니, 채택한 타입마다 직접 구현해야 한다. (다만, 프로토콜 익스텐션으로 어느 정도 보완 가능하다.)
  • 명시적 채택 필요: 상속은 자동으로 기능을 물려받지만, 프로토콜은 채택과 구현을 명시적으로 해야 한다.

 

3. 상속 vs 프로토콜: 차이점 비교

  상속 프로토콜
사용 대상 클래스만 가능 클래스, 구조체, 열거형 가능
다중 지원 단일 상속만 가능 다중 채택 가능
기본 구현 부모 클래스의 코드 상속 기본 구현 없음 (익스텐션 가능)
관계 "is-a" 관계 (예: Dog is Animal) "can-do" 관계 (예: Can fly)

쉽게 말해, 상속은 "무엇이다"라는 관계를 표현하고, 프로토콜은 "무엇을 할 수 있다"를 정의한다.

 

 

프로토콜 지향 프로그래밍? (Protocol Oriented Programming)

프로토콜에 관하여 알아보던 중 객체 지향 프로그래밍은 들어봤지만, 프로토콜 지향 프로그래밍이라는게 있었다는 것을 이번에 처음 알았다.

몰랐었는데, Swift는 프로토콜 지향 언어이며 2015년 애플의 WWDC(세계 개발자 컨퍼런스)에서 Swift 언어와 함께 공식적으로 소개되었다고 한다.

 

스위프트에서의 String, Int, Float, Date 등드 기본 타입은 대부분 구조체로 구현되어있고, Array, Set, Dictionary 또한 구조체로 구현되어 있다.

구조체는 클래스와 달리 상속이 불가능한데 다양한 공통 기능을 가질 수 있던 이유가 바로 Protocol 그리고 Extension 때문이었다.

 

그럼 객체 지향 프로그래밍과의 차이점은 뭘까?

 

1. 상속 vs 합성: 객체 지향 프로그래밍은 클래스 상속을 통해 코드를 재사용하지만, 프로토콜 지향 프로그래밍은 프로토콜 채택과 확장을 통해 여러 소스에서 기능을 합성한다.

 

2. 다중 상속의 문제 해결: 클래스 기반 언어에서 다중 상속은 다이아몬드 문제 등 복잡성을 야기할 수 있지만, 프로토콜은 여러 프로토콜을 동시에 채택할 수 있어 이 문제를 해결한다.

 

3. 값 타입 활용: 프로토콜 지향 프로그래밍은 클래스(참조 타입)뿐만 아니라 구조체와 열거형 같은 값 타입에도 적용할 수 있어 더 유연하다.

 

프로토콜 확장(Protocol Extensions)을 통해 프로토콜에 기본 구현을 제공하는 간단한 코드 예시.

// 프로토콜 정의
protocol Drawable {
    func draw()
}

// 프로토콜 확장으로 기본 구현 제공
extension Drawable {
    func draw() {
        print("기본 그리기 구현")
    }
    
    func prepare() {
        print("그리기 준비")
    }
}

// 구조체에서 프로토콜 채택
struct Circle: Drawable {
    // draw() 메서드를 재정의하지 않으면 기본 구현 사용
}

struct Rectangle: Drawable {
    // draw() 메서드 재정의
    func draw() {
        print("사각형 그리기")
    }
}

let circle = Circle()
circle.draw()  // 출력: "기본 그리기 구현"
circle.prepare()  // 출력: "그리기 준비"

let rectangle = Rectangle()
rectangle.draw()  // 출력: "사각형 그리기"

 

 

반응형