클라이언트는 그들이 사용하지 않는 인터페이스에 의존해서는 안된다.
불필요한 인터페이스 요소들을 포함시키지 말라는 의미이다. 불필요한 요소들이 포함되면서 복잡해지고, 무거워짐에 따라 진작 원하는 정보를 얻을 수 없는 지경에까지 이르기도 한다. 이 문제는 클래스나 프로토콜 모두에게 영향을 줄 수 있다.
Protocol
protocol의 경우를 먼저 본다.
"터치"를 했을 때 반응을 구현해줄 didTap 메서드를 가지고 있는 GuestureProtocol을 보자.
protocol GusetureProtocol{
func didTap()
}
이후에 더 많은 제스처들을 추가해주고싶어서 프로토콜에 추가한다면?
protocol GusetureProtocol{
func didTap()
func didDoubleTap()
func didLongPress()
}
그리고 실제로 사용할 때에는 프로토콜을 채택하고 그 메서드들을 구현해주면 된다.
class SuperButton: GusetureProtocol{
func didTap() {
<#code#>
}
func didDoubleTap() {
<#code#>
}
func didLongPress() {
<#code#>
}
}
문제는 여기서 발생한다 만약 didTap만을 지원하는 버튼을 만들고자 한다면 어떻게 해야할까? 따로 메서드를 만들지, 아니면 프로토콜을 채택하고 나머지 메서드들은 더미하게 구현해야할지 싶을거다.
하지만 이렇게 구현하는 것 자체가 ISP를 위반하는 "Fat"한 인터페이스이다. 그렇기에 필요한 기능만 골라서 사용할 수 있도록 프로토콜을 나눠서 구현해주는 방식으로 구성해야한다.
protocol TapProtocol {
func didTap()
}
protocol DoubleTapProtocol {
func didDoubleTap()
}
protocol LongPressProtocol {
func didLongPress()
}
class SuperButton: TapProtocol, DoubleTapProtocol, LongPressProtocol {
func didTap() {
// send tap action
}
func didDoubleTap() {
// send double tap action
}
func didLongPress() {
// send long press action
}
}
class PoorButton: TapProtocol {
func didTap() {
// send tap action
}
}
이렇게 프로토콜마다 메서드를 하나씩 만들어주게되면, 원하는 프로토콜만 채택하여 기능을 구현할 수 있게 된다.
Class의 경우
영상에 대한 정보를 포함하고 있는 Video라는 클래스가 있다고 해보자.
class Video {
var title: String = "My Video"
var description: String = "This is a beautiful video"
var author: String = "Marco Santarossa"
var url: String = "https://marcosantadev.com/my_video"
var duration: Int = 60
var created: Date = Date()
var update: Date = Date()
}
그리고 play라는 메서드에 비디오 정보를 넣어준다.
func play(video: Video) {
// load the player UI
// load the content at video.url
// add video.title to the player UI title
// update the player scrubber with video.duration
}
play메서드에는 title, rul, duration만 필수적인 정보이고 나머지는 굳이 받아야 할 필요가 없다.
이런 경우 또한 protocol을 정의해줌으로써 play메서드가 필요로하는 정보만 전달해주면 된다.
protocol Playable {
var title: String { get }
var url: String { get }
var duration: Int { get }
}
class Video: Playable {
var title: String = "My Video"
var description: String = "This is a beautiful video"
var author: String = "Marco Santarossa"
var url: String = "https://marcosantadev.com/my_video"
var duration: Int = 60
var created: Date = Date()
var update: Date = Date()
}
func play(video: Playable) {
// load the player UI
// load the content at video.url
// add video.title to the player UI title
// update the player scrubber with video.duration
}