# ISP: 인터페이스 분리 원칙 - 인터페이스는 클라이언트가 사용하지 않는 메서드에 의존하면 안된다! - 한 인터페이스가 너무 많은 기능을 포함하지 않도록 하는 것을 목표로 하며, 각 클라이언트는 자신이 사용하지 않는 메서드에 영향을 받지 않아야 합니다. - 큰 덩어리의 인터페이스들을 구체적으로 작은 단위들로 분리시켜 클라이언트들이 꼭 필요한 메서드만 사용할 수 있게 해야 함 - 목적은 결합도를 낮추고, 유연성과 확장성을 높이기 위해 사용하기 위해 - 간단한 예 - UITableViewDataSource, UITableViewDelegate의 분리 - 하나만 쓰는경우도 있으니깐? 분리를 잘했다. - 일단 Swift에서는 POP로 통한다 가즈아! ## POP - POP를 제대로 하기 위해서는 ISP를 제대로 이해하고 습관화 해야함 - 고전적인 ISP abstract class를 주로 이용하지만 swift에서는 protocol를 이용 - ISP에 따라 작게 분해된 인터페이스을 이용해 만들어가는것이 POP ```swift protocol Openable { func open() } protocol Closable { func close() } protocol DorrControllable: Openable, Closable {} ``` ```swift class AutomaticDoor: Openable { func open() { print("자동 문이 열렸습니다.") } } class ManualDoor: Closable { func close() { print("수동 문이 닫혔습니다.") } } class SecurityDoor: DoorControllable { func open() { print("보안 문이 열렸습니다.") } func close() { print("보안 문이 닫혔습니다.") } } ``` - 이러는 방법이 있다 하지만 추가적인 방법은 (아래 추가했음!) ```swift class DoorUser { func operateDoor<T: DoorControllable>(doorController: T) { doorController.open() doorController.close() } } // 위 아래 취향 차이? 선택 class DoorUser { func operateDoor(doorController: Openable & Closable) { doorController.open() doorController.close() } } let automaticDoor = AutomaticDoor() let manualDoor = ManualDoor() let securityDoor = SecurityDoor() let doorUser = DoorUser() doorUser.operateDoor(doorController: automaticDoor) doorUser.operateDoor(doorController: manualDoor) doorUser.operateDoor(doorController: securityDoor) ``` ### ISP를 어긴 코드 간단한 예시 ```swift protocol DoorControllable { func operate() } class AutomaticDoor: DoorControllable { func operate() { print("자동 문이 열렸습니다.") print("자동 문이 닫혔습니다.") } } class ManualDoor: DoorControllable { func operate() { print("수동 문이 열렸습니다.") print("수동 문이 닫혔습니다.") } } ``` - 대충 이런식이다. 흠 이렇게 써보니깐 단일책임이랑 너무 같은거 같은데? 차이가 뭐야? (메서드-> 단일, 인터페이스를 나눠야한다 프로토콜 하나가에서 하는게 아니라 그걸 나누는것이 ISP다) - ISP를 잘지키면 불필요한 기능구현 및 코드 재건축을 방지할 수 있고, 코드의 이해도와 테스트 용이성 측면에도 좋은것같습니다, 이를 위해 작은 단위로 책임을 나눠서 인터페이스(swift:프로토콜, ???: abstractClass)를 구현한다. - 인터페이스 분리 원칙을 준수하면서 각 인터페이스이 하나의 책임에 집중하는 경우가 많다. - 프로토콜이 하나의 기능에 집중하고 있으며,이들을 조합하여 여러 종류의 동작을 하는 클래스를 만들 수 있습니다. 그리고 이런 클래스들을 사용하는 클라이언트 코드는 필요한 동작에만 의존할 수 있게 됩니다. - 따라서 제가 앞에 한것들은 인터페이스 분리, 단일 책임, 2가지의 원칙이 적용된 것입니다!(클래스는 각각책임, 클라이언트 코드는 필요한 동작만 의존) #### 자 다음은 DIP 나와! 의존성 역전 해줘! 진행해줘! - 위에서 프로토콜을 생성후에 클래스에서 채택해서 만들어서 사용 진행했습니다. 하지만 추가적으로 가능하게 프로토콜을 확장해서 사용도 가능합니다! ```swift protocol Openable { func open() } protocol Closable { func close() } protocol DoorControllable: Openable, Closable {} extension Openable { func open() { print("문이 열렸습니다.") } } extension Closable { func close() { print("문이 닫혔습니다.") } } ``` - 이렇게 사용도 가능합니다 추가적으로 공통 구현을 했지만 필요한 경우네는 오버라이드 하여 변경할 수 있게 진행하기! 요호호