Class(OOP) VS Struct, Enum(POP)
- Encapsulation: 그룹화
- Access Control: 접근 제어자
- Abstraction: 추상화
- Namespace: software가 커지면서 발생하는 충돌을 막아준다
- Expressive Syntax: 저장/연산 프로퍼티, 메소드, 서브스크립션..
- Extensibility: 나중에 필요한거 추가 가능
Access Control, Abstraction, Namespace는 특히 복잡성(Complexity)을 관리하게 해줍니다.
- struct, enum도 할 수 있음.
- Swift에서 이름 지을 수 있는 모든 type은 일급객체이고 위에 모든 특징을 갖을 수 있다.
The Three Beefs
1. Implicit Sharing
- 값 타입은 참조를 공유해 의도하지 않은 변화가 발생해 문제될 수 있다.
2. Inheritance All Up In Your Business
- Superclass 1개만 갖을 수 있다.
- 필요 없는것도 다 상속 받음
- class를 정의하는 순간 super class를 정해야한다.(extension으로 상속 불가능)
- Superclass에 저장 프로퍼티가 있다면
- 상속 받아야만 한다.
- 저장프로퍼티들을 초기화 해줘야한다.
- superclass의 invariant를 깨면안된다.
- method들이 override될 건가 알아야한다.(final 키워드 명시)
- cocoa에서 delegate 패턴을 사용하는 이유입니다.
3. Lost Type Relationships
- Ordered의 precedes의 구현부에 어쩔수 없이 불안한 구현
- Number의 precede의 other은 Label이 될 수 도 있다.(static type safety hole)
- as! ASubclass은 code smell 이다.
- as! ASubclass은 type relationship이 손상됐음을 의미한다.
- Swift는 정적 타입 언어로 변수, 상수의 타입이 컴파일 시점에 결정되는데 타입 캐스팅을 사용하면 런타임에 타입이 정해져 캐스팅에 실패하는 경우 런타임에 오류가 발생할 수 있다.
Swift Is a Protocol-Oriented Programming Language
Start with a Protocol
Your first stop for new abstractions
- Ordered의 불필요한 구현부 삭제(fatal error 신경쓰지 않아도 됨)
- override 여부를 신경쓰지 않아도 됨
- 상속을 사용하지 않음으로 class -> struct로 변경
- 강제 타입캐스팅(static type safety hole) 제거
- Self는 자기 자신의 타입을 나타낸다.
Using Our Protocol
- Ordered는 Label이 될 수 도있고 Number가 될수도있는 heterogeneous인 array라 컴파일러가 Homogeneous인 array로 바꾸라고한다.
- generic을 사용하면 Homogeneous인 array로 인식시킬 수 있다.
Protocols and Generics for Testability
- extension을 사용해 반복되는 구현을 한번만 구현해 사용한다.
- circleAt은 요구사항에 있고, extension에 구현
- rectangleAt은 요구사항에 없고, extension에 구현
- type inference을 시킬 경우에는 둘다 새로 커스텀한게 실행된다.
- type annotation 하면 요구상항에 없는 retangleAt은 커스텀한 부분이 아니라 protol의 extension에 구현한 부분이 실행된다.
More Protocol Extension Tricks
Scenes from the standard library and beyond
Constrained extensions
- 어떤 collection의 요소들은 == 로 비교할 수 없다.
- where을 사용해 Equatable Protocol을 따르는 element들만 연산할 수 있게 수정
Retroactive adaption
- Int는 Ordered 프로토콜을 채택하지 않아 사용이 불가능함
- Int, String 이 Ordered 프로토콜을 채택하게해 사용가능하게 함
- Comparable 프로토콜에는 '<' 연산자가 이미 존해한다.
- Comparable에서 extension을 통해 precedes를 구현해 개선
- Comparable을 확장해 Double 타입이 precedes 메소드를 사용할 수 있지만 Ordered 프로토콜을 채택하지 않아 Double 타입에서 binarySearch 메소드는 사용 불가능하다
- constrained extension 사용해 Ordered 확장해 Ordered를 채택한 타입만 precedes 메소드와 binarySearch 메소드를 사용할 수 있게 함
Generic beautification
- Swift1 의 fully generallized binary search
- Swift2 에서 Protocol을 사용해 개선
Interface generation
- Protocol을 채택하면 extension에 구현된 인터페이스들 사용가능
Building bridges between the static and dynamic worlds
- 배열의 count 가 같고 하나씩 비교해 같은지 확인
- Drawable은 Equatable 프로토콜을 채택하지 않아서 == 연산자로 비교할 수 없다.
- Equatable 프로토콜을 Self를 사용해 비교(Static Dispatch, Homogeneous)하는데 Drawable은 Circle이 될수도 Polygon이 될수도 있어(Dynamic Dispatch, Heterogeneous)서 충돌한다.
- extension을 통해 다운 캐스팅을 통해서 type을 변형하면 Equatable을 채택하고 Self를 사용해 비교할 수 있다.
- Static Dispatch -> Dynamic Dispatch로 변경
- Heterogeneous -> Homogeneous로 변경
They(Classes) do have their place...
implicit한 공유가 필요할 때
- 복사나 비교가 의미없는상태(Singleton 처럼 한번 만들어 놓고 쓰는거 말하는거 같음)(e.g., Window)
- 인스턴스의 생명주기가 외부요인과 관련있을때(e.g., TemporaryFile)
- reference type은 안전한 identity가 있어 외부의 entity와 correspond하는 먼가를 만든다면 참조 타입을 사용해야 한다.
- 인스턴스는 데이터의 구조를 정의하고 상태를 저장하는데 사용되고 메서드는 해당 객체가 아닌 외부에서 수행한다.(e.g., CGCContext)
- 주의 사항
- final로 선언
- base class 없이 Protocol 사용
Don't fight the system
On the other hand, be circumspect
- software 안에서 구성요소가 너무 커지게 하면안된다.
- class를 사용하기전에 class를 사용하지 않는 방법을 고려해 봐라
참고