다형성(Polymorphism)
OOP의 4가지 특성(상속, 추상화, 캡슐화, 다형성) 중 하나인 다형성은 무엇을 뜻하는 것일까요?
다형성의 관용적인 개념은 같은 모양의 코드가 다른 행위를 하는 것을 뜻합니다.
즉, 어떤 객체의 속성이나 기능이 상황에 따라 여러 가지 형태를 가질 수 있는 성질을 뜻하는 것입니다.
마치 핸드폰 속 키보드를 통하여 다이얼을 누르기도 하고, 문자를 하기도 하며, 게임도 하는 것과 같이 모양은 같지만 서로 다른 기능을 하고있는 것을 디바이스 기반의 다형성이라고 할 수 있습니다.
이것은 프로그래밍 언어의 각 요소들(상수, 변수, 객체, 메소드 등)이 다양한 자료형에 속하는 것을 허가하는 성질이라도 할 수 있습니다.
위의 키보드 예시에서는 각각의 역할이 있지만, 결국은 다 키보드라는 하나의 디바이스로서 모든 역할들을 아우를 수 있는 것과 같다고 볼 수 있습니다.
Swift 내의 다형성
그렇다면 Swift 내에서의 다형성은 무엇이 있을까요?
Overriding
슈퍼 클래스를 상속받는 여러 서브 클래스들이 같은 이름이지만 다른 기능을 하는 메소드를 정의하고 사용할 수 있습니다.
우리는 이것을 메소드 오버라이딩이라고 합니다.
마치, Vehicle(탈 것)이라는 슈퍼 클래스가 존재하고, 서브 클래스인 Car와 Bicyle이 있다고 가정해봅시다.
Vehicle은 ride()라는 메소드가 존재하고, 두 자식 클래스도 ride()라는 메소드를 가지고 있지만, 각각 overriding을 통하여 차는 엑셀을 밟는다, 자전거는 페달을 밟는다라고 맞게 변경할 수 있는 것과 같습니다.
Overloading
동일한 이름의 메소드가 매개변수의 이름, 타입, 개수 등의 차이로 인해서 다르게 움직이는 것을 말합니다.
추상화 vs 다형성
그렇다면 추상화(Abstraction)과의 차이점은 무엇일까요?
먼저 추상화는 ‘사물이나 표상을 어떤 성질, 공통성, 본질에 착안하여 그것을 추출하여 파악하는 것’입니다.
즉, 여기서 핵심은 공통성과 본질을 모아 추출하는 것입니다.
Swift에서는 Abstract class(Super Class)와 Protocol로 추상화를 할 수 있습니다.
앞선 예에서 Car와 Bicycle은 Vehicle로 추상화를 할 수 있겠네요.
Vehicle을 예로 들어보면서 추상화와 다형성에대해서 더 이해를 해보겠습니다.
아래와 같이 Driver Class가 있다고 생각을 해보겠습니다. 그리고 Driver는 차와 자전거를 운전할 수 있다고 가정해보겠습니다.
먼저 Bicycle과 Car의 코드는 아래와 같게됩니다.
class Bicycle {
func pressPedal() {
// 페달을 밟는다.
}
}
class Car {
func pressAccel() {
// 악셀을 밟는다.
}
}
그리고, Driver 클래스의 코드는 아래와 같이 됩니다.
class Driver {
let bicycle = Bicycle()
let car = Car()
func rideBicycle() {
// 자전거를 운전한다.
self.bicycle.pressPedal()
}
func rideCar() {
// 자동차를 운전한다.
self.car.pressAccel()
}
}
위와 같은 코드는 문제가 많습니다.
- Driver는 Car와 Bicyle만 운전할 수 있는 것이 아니라, 다른 이동수단들도 탈 수 있게된다면?
- 매번 Driver 클래스 안에 새로운 함수와 프로퍼티 값을 추가해주어야하나..
- Driver 클래스와 각각의 클래스들의 결합도가 매우 높은 상태입니다.
- 만약 Car의 메소드의 이름이 변경된다면 Driver의 메소드도 같이 변경되어야합니다.
이러한 문제점들을 해결할 수 있는 것이 추상화와 다형성입니다.
우리는 Car, Bicycle을 Vehicle이라는 class로 추상화를 하고, 해당 class를 상속받는 Car와 Bicycle을 정의해줍니다.
이렇게 할 경우, 아래와 같이 Driver 코드가 변경이되고, Vehicle 클래스를 새롭게 정의할 수 있습니다.
class Driver {
let vehicle: Vehicle
init(vehicle: Vehicle) {
self.vehicle = vehicle
}
func ride() {
self.vehicle.ride()
}
}
class Vehicle {
func ride() {
// 운전하기!
}
}
Bicycle과 Car는 아래와 같이 Vehicle을 상속 받습니다.
class Bicycle: Vehicle {
override func ride() {
// 페달을 밟는다.
}
}
class Car: Vehicle {
override func ride() {
// 악셀을 밟는다.
}
}
위와 같은 코드에서 Driver는 어떤 이동수단을 타는 지 정확히 모르는 상태에서 ride라는 메소드를 호출하기만 하면 알아서 자신의 이동수단으로 이동을 할 수 있습니다.
Driver는 그냥 메소드를 호출만 시키면 알아서 나머지 로직이 진행이 됩니다. + Driver는 각 구체타입 별로 메소드를 가지고 있을 필요가 없습니다.
즉, 객체간의 결합도가 낮아짐을 알 수 있죠. 또한, Car의 메소드가 수정이된다고 해도, 전의 상황과 같이 Driver 속 코드까지 변경할 필요가 없습니다.
위와 같은 장점은 추상화를 통해서 얻을 수 있었습니다.
또한, 각 서브 클래스는 ride()함수를 overriding하여 각자 원하는 방식으로 자신들을 이동시키는 메소드를 구현할 수 있습니다.
즉, 다형성을 통하여 Vehicle 및 Vehicle의 ride()라는 메소드를 내가 원하는 만큼 다양하게 구체화할 수 있습니다.
다형성과 추상화는 밀접하게 연관되어있습니다.
제가 생각하기에 추상화는 정의 그대로 비슷한 성질을 가지고 있는 타입들을 하나의 타입으로 묶어주는 것이고, 그러한 추상화를 통하여 여러 이점들을 극대화시킬 수 있는 것이 다형성이라는 생각이 듭니다.
(아직 부족하기에 계속 보완해나가고 있습니다. 잘못된 점 말씀해주시면 감사하겠습니다☺️)
'Swift' 카테고리의 다른 글
[Swift] WWDC16 Understanding Swift Performance(1) (0) | 2023.07.31 |
---|---|
[Swift] 다형성을 활용하여 Enum 대체하기 (0) | 2023.07.26 |
[Swift] IUO(옵셔널 암시적 추출) (0) | 2023.06.12 |
[Swift] self는 언제 쓸까? (0) | 2023.04.13 |
[Swift] initializers(생성자) (0) | 2023.03.17 |