ISP: 인터페이스 분리 원칙

2023. 12. 3. 14:04swift

- 인터페이스는 클라이언트가 사용하지 않는 메서드에 의존하면 안된다!
    - 한 인터페이스가 너무 많은 기능을 포함하지 않도록 하는 것을 목표로 하며, 각 클라이언트는 자신이 사용하지 않는 메서드에 영향을 받지 않아야 합니다.
- 큰 덩어리의 인터페이스들을 구체적으로 작은 단위들로 분리시켜 클라이언트들이 꼭 필요한 메서드만 사용할 수 있게 해야 함
- 목적은 결합도를 낮추고, 유연성과 확장성을 높이기 위해 사용하기 위해
- 간단한 예
    - UITableViewDataSource, UITableViewDelegate의 분리
    - 하나만 쓰는경우도 있으니깐? 분리를 잘했다.

- 일단 Swift에서는 POP로 통한다 가즈아!

 POP

- POP를 제대로 하기 위해서는 ISP를 제대로 이해하고 습관화 해야함
- 고전적인 ISP abstract class를 주로 이용하지만 swift에서는 protocol를 이용
- ISP에 따라 작게 분해된 인터페이스을 이용해 만들어가는것이 POP

protocol Openable {
    func open()
}

protocol Closable {
    func close()
}

protocol DorrControllable: Openable, Closable {}
class AutomaticDoor: Openable {
    func open() {
        print("자동 문이 열렸습니다.")
    }
}

class ManualDoor: Closable {
    func close() {
        print("수동 문이 닫혔습니다.")
    }
}

class SecurityDoor: DoorControllable {
    func open() {
        print("보안 문이 열렸습니다.")
    }
    
    func close() {
        print("보안 문이 닫혔습니다.")
    }
}


- 이러는 방법이 있다 하지만 추가적인 방법은 (아래 추가했음!)

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를 어긴 코드 간단한 예시

protocol DoorControllable {
    func operate()
}

class AutomaticDoor: DoorControllable {
    func operate() {
        print("자동 문이 열렸습니다.")
        print("자동 문이 닫혔습니다.")
    }
}

class ManualDoor: DoorControllable {
    func operate() {
        print("수동 문이 열렸습니다.")
        print("수동 문이 닫혔습니다.")
    }
}


- 대충 이런식이다. 흠 이렇게 써보니깐 단일책임이랑 너무 같은거 같은데? 차이가 뭐야? (메서드-> 단일, 인터페이스를 나눠야한다 프로토콜 하나가에서 하는게 아니라 그걸 나누는것이 ISP다)
- ISP를 잘지키면 불필요한 기능구현 및 코드 재건축을 방지할 수 있고, 코드의 이해도와 테스트 용이성 측면에도 좋은것같습니다, 이를 위해 작은 단위로 책임을 나눠서 인터페이스(swift:프로토콜, ???: abstractClass)를 구현한다.
- 인터페이스 분리 원칙을 준수하면서 각 인터페이스이 하나의 책임에 집중하는 경우가 많다.
- 프로토콜이 하나의 기능에 집중하고 있으며,이들을 조합하여 여러 종류의 동작을 하는 클래스를 만들 수 있습니다. 그리고 이런 클래스들을 사용하는 클라이언트 코드는 필요한 동작에만 의존할 수 있게 됩니다.
- 따라서 제가 앞에 한것들은 인터페이스 분리, 단일 책임, 2가지의 원칙이 적용된 것입니다!(클래스는 각각책임, 클라이언트 코드는 필요한 동작만 의존)
 
- 위에서 프로토콜을 생성후에 클래스에서 채택해서 만들어서 사용 진행했습니다. 하지만 추가적으로 가능하게 프로토콜을 확장해서 사용도 가능합니다!

protocol Openable {
    func open()
}

protocol Closable {
    func close()
}

protocol DoorControllable: Openable, Closable {}

extension Openable {
    func open() {
        print("문이 열렸습니다.")
    }
}

extension Closable {
    func close() {
        print("문이 닫혔습니다.")
    }
}


- 이렇게 사용도 가능합니다 추가적으로 공통 구현을 했지만 필요한 경우네는 오버라이드 하여 변경할 수 있게 진행하면 됩니다!!

 

'swift' 카테고리의 다른 글

Swift에서 크래시안나게 하는 습관  (0) 2024.04.15
ARC  (2) 2024.01.08
LLVM 에 대해서 알아보자.  (0) 2023.09.18
Swift 의 장점에 대해서!  (0) 2023.08.22
구조체와 클래스  (0) 2023.08.22