Protocol Oriented Programming에 대한 얕은 공부
Swift는 프로토콜 지향 언어라고 한다. 아직도 대부분 클래스를 사용하고 구조체, 열거형 등은 특별한 경우에만 쓰는 나로서는 Swift의 특징적인 면을 제대로 이해하지 못 하고 사용하고 있다는 느낌을 받았다. 그래서 이번 주제로 잡고 조사하게 되었다.
POP가 나오게 된 배경
기존의 객체 지향 프로그래밍에서는 공통된 기능을 Class의 상속을 통해 구현한다. Swift도 많은 부분이 Class로 이루어져 있다. 대표적인 것이 UIViewController
일 것이다. 그런데 참조 타입의 경우 다중 스레드 환경 같은 곳에서 원본 데이터가 바뀔 수 있기 때문에 값 타입을 사용하는 것이 권장되고 있다. 그렇지만 Struct나 Enum의 경우 상속이 불가능하기 때문에 공통적인 기능을 어떻게 구현할지 의문이 생긴다.
이 의문에 대한 답으로 2015년 애플은 Swift 2의 Extension
을 제시하였다. Protocol과 Extension
의 조합으로 Protocol은 메서드, 프로퍼티 등 구현해야 할 사항들을 모아놓은 껍데기에서 구현까지 할 수 있게 되었다. 이것을 Protocol Default Implementation, 프로토콜 초기 구현이라고 하고 이를 통해 Class의 상속과 같이 공통된 기능을 구현할 수 있게 되어 POP가 가능하게 되었다.
프로토콜 초기 구현(Protocol Default Implementation)
프로토콜의 한계
프로토콜은 위에서 언급했듯이 일종의 설계도일 뿐 그 속에 실제 값들을 담지 못 한다. 그래서 다음과 같은 일이 일어난다.
1 | protocol Person { |
getAge()
메서드는 하는 일이 같은데도 불구하고 구현부를 따로 둬야 하기 때문에 중복으로 구현해야하는 문제가 발생한다.
Extension 적용
여기서 사용할 수 있는 것이 Extension
이다. 다음과 같이 구현하면 된다.
1 | protocol Person { |
Extension
을 통해 Person 프로토콜의 getAge()
메서드를 미리 구현하여 Person 프로토콜을 준수하는 구조체가 따로 구현할 필요없이 사용할 수 있다. 그런데 만약 변형해서 사용하고 싶다면 사용하는 클래스 내애서 재정의하여 사용하면 된다.
Protocol과 Generic
프로토콜은 Generic
과 AssociatedType
을 적용하면 더욱 더 재사용성을 높일 수 있다.
1 | protocol Box { |
프로토콜 추가
여기서 새로운 기능을 추가할 경우 Extension
으로 새로운 프로토콜을 따르게 하면 된다.
1 | protocol Printable { |
POP의 이점
- 가볍고 안전하다.
굳이 알려주지 않아야 할 것은 알려주지 않아도 되고 그로 인해 필요한 것만 쓸 수 있다.
1 | protocol Car { |
값 타입의 상속 효과
위에서 보듯이 값 타입도 공통된 기능을 쉽게 구현할 수 있다.수평적인 기능 확장
Class는 하나의 상속만 가능하고 수직적인 구조를 고려하여야 하지만 Protocol은 마치 블럭처럼 기능을 추가할 수 있다.제네릭의 활용
자료형의 구애를 받지 않는 제네릭을 활용하였을 때 POP의 힘은 훨씬 강력해진다고 한다. Swift의Array
타입을 예로 들 수 있겠다. 수많은 프로토콜을 준수하는Array
타입은 타입에 관계없이 만들 수 있으며 그에 따른 메서드들도 다양하게 지원이 된다.
이번 공부를 하면서 느낀 것은 Swift 언어가 깊이 들어갈수록 배울 것이 많아지고 그만큼 활용성이 커진다는 것이다. POP를 당장 활용할 수는 없겠지만 좀 더 유연한 사고를 가지고 이것을 직접 적용해보는 시간을 점차 늘려야겠다.