| 객체 지향 프로그래밍(OOP) | 프로토콜 지향 프로그래밍(POP) |
|---|---|
| 클래스 상속을 사용하여 기능을 확장한다 | 프로토콜 채택 및 프로토콜 확장을 사용하여 기능을 확장한다 |
| 클래스 상속은단일 상속만 가능하며, 다중 상속을 지원하지 않는다 | 여러 개의 프로토콜을 동시에 채택할 수 있어 다중 상속과 유사한 구성을 할 수 있다 |
| 클래스 상속은 상위 클래스의 메모리 구조를 강제로 따르도록 한다 | 프로토콜은 메모리 구조에 대한 특정 요구 사항이 없기 때문에 유연하다 |
| 클래스 상속은 불필요한 속성과 메서드까지 상속받을 수 있다 | 프로토콜은 필요한 기능만 채택할 수 있으므로 메모리 사용 측면에서 효율적이다 |
| 상속을 이용한 확장은 클래스(Reference Type)에서만 가능하다 | 프로토콜은 모든 타입에서 사용할 수 있다(클래스, 구조체, 열거형) |
| 런타임에 메서드를 동적으로 찾는다(동적 디스패치) | 컴파일 타임에 메서드를 정적으로 찾는다(정적 디스페치) |
| 주로 클래스 타입을 사용한다 | 값 타입(구조체, 열거형)을 적극 활용할 수 있다 |
@objc optional 지원)let device: Device)Int, String 등)// 기본 기능을 정의하는 프로토콜
protocol Drawable {
func draw() // 그림을 그리는 기능을 요구하는 메서드
}
protocol Scalable {
func scale(by factor: Double) // 크기를 조정하는 기능을 요구하는 메서드
}
// 두 개의 프로토콜을 조합하여 만든 상위 프로토콜 (다중 프로토콜 상속)
protocol AdvancedDrawable: Drawable, Scalable {}
// 기본 구현을 제공하는 확장 (모든 Drawable 타입에 적용)
extension Drawable {
func draw() {
print("도형을 그립니다") // 기본 구현 제공 (확장을 사용하여 모든 Drawable에 제공)
}
}
// 기본 구현을 제공하는 확장 (모든 Scalable 타입에 적용)
extension Scalable {
func scale(by factor: Double) {
print("크기를 \(factor)배로 조정합니다") // 기본 구현 제공 (확장을 사용하여 모든 Scalable에 제공)
}
}
// 기존 타입(Int)에 프로토콜을 소급 적용하여 기능 추가하기 (Retroactive Conformance)
extension Int: Drawable {
func draw() {
print("정수를 그립니다: \(self)") // Int 타입도 Drawable 프로토콜을 채택하여 기능을 추가함
}
}
// 새로운 타입 정의 (구조체도 프로토콜을 채택할 수 있음)
struct Rectangle: AdvancedDrawable {
var width: Double
var height: Double
func area() -> Double { // Rectangle 고유의 메서드 (프로토콜 요구사항과 무관)
return width * height
}
}
// 사용 예제
let rect = Rectangle(width: 10, height: 5)
rect.draw() // 출력: 도형을 그립니다 (프로토콜 확장의 기본 구현 사용)
rect.scale(by: 2.0) // 출력: 크기를 2.0배로 조정합니다 (프로토콜 확장의 기본 구현 사용)
print("면적: \(rect.area())") // 출력: 면적: 50.0
let num: Int = 10
num.draw() // 출력: 정수를 그립니다: 10 (소급 적용된 기능 사용)