인터페이스란?
해당 소프트웨어개발의 표준명세서(약속)라고 할 수 있습니다
인터페이스를 통해 일관된 틀 안에서 정형화된 작업을 진행할 수 있습니다.
추상함수와 속성(kotlin interface 특징)으로 구성됩니다.
서로 관계없는 클래스를 인터페이스 구현을 통해 공통 관계를 맺게 해줄 수 있다.
클래스의 선언과 구현을 분리함으로써 독립적인 프로그래밍이 가능해집니다.
하나의 클래스에 변경이 있더라도 다른 클래스에 영향을 끼치지 않게 됩니다.
인터페이스와 구현클래스를 나누어 작업하면 개발 기간을 단축시킬 수 있습니다.
만약 내가 리포지토리를 작업해야 하고 동료가 데이터소스를 작업해야 할 때 리포지토리에서 사용할 데이터소스의 인터페이스를 먼저 작성해놓으면 동료가 데이터소스 구현클래스를 완성할때까지 기다릴 필요 없이 리포지토리 작업을 진행할 수 있습니다.
아래에 영화 정보를 API를 통해 가져오는 리포지터리가 있습니다.
class MovieRepository {
private val dataSource = TMDBDataSource()
fun getNowPlaying(): List<Movie> {
val nowPlaying = dataSource.getNowPlaying()
...
}
}
MovieRepository는 데이터소스로 TMDBDataSource라는 객체를 사용하고 있습니다.
TMDBDataSource는 웹사이트인 TMDB에서 제공하는 rest api를 통해 영화 정보를 가져올 수 있습니다.
하지만 개발 도중 TMDB사이트가 해킹 사태로 인해 api를 제공하지 못하게 되었습니다.
TMDB api를 사용하기위해 TMDBDataSource 클래스를 작성한 것인데 사용할 수가 없게 되었습니다.
따라서 TMDB API 대신 Naver 영화 API를 사용하기 위해 NaverDataSource라는 클래스롤 새로 작성했습니다.
이렇게 datasource가 변경될 경우 repository에서도 사용하는 datasource를 변경해줘야 합니다.
class MovieRepository {
private val dataSource = NaverDataSource()
fun getNowPlaying(): List<Movie> {
val nowPlaying = dataSource.getNowPlaying()
...
}
}
서로 의존 관계가 있는 객체 중 한 쪽의 변경이 있으면 다른 한 쪽도 영향을 끼칠 수 밖에 없습니다.
이를 객체지향 개념 중 다형성과 인터페이스를 사용해 해결할 수 있습니다.
먼저 datasource 인터페이스를 아래와 같이 작성해주고
interface MovieDataSource {
fun getNowPlaying(): List<Movie>
...
}
작성한 인터페이스를 구현하는 구현 클래스를 작성합니다.
이 때 Naver API를 사용하는 코드로 getNowPlaying()메서드를 오버라이딩 해줍니다.
class NaverMovieDataSource: MovieDataSource {
override fun getNowPlaying(): List<Movie> {
val nowPlayingList = NaverMovieAPI.getNowPlaying()
return nowPlayingList
}
...
}
이제 repository에는 datasource 구현 객체를 직접 사용하지 않고 인터페이스 타입의 객체를 파라미터로 받아와 사용할 수 있게 됩니다.
class MovieRepository(dataSource: MovieDataSource) {
fun getNowPlaying(): List<Movie> {
val nowPlaying = dataSource.getNowPlaying()
...
}
}
repository의 입장에서 dataSource가 tmdb api로 받아온 데이터인지 naver api로 받아온 데이터인지 알 필요 없이 영화 데이터를 받고 viewmodel 또는 usecase에 데이터를 반환할 수 있습니다.
인터페이스를 통해 repository가 datasource의 결합도를 낮출 수 있게 되었습니다.
개발자 입장에서도 repository를 담당하는 개발자는 datasource의 변경사항에 관계없이 repository 개발에만 집중할 수 있고, datasource를 담당하는 개발자 역시 interface를 구현하는 datasource 클래스를 작성하며 일관적인 기능 개발을 수행할 수 있게 됩니다.
하지만 이러한 개발 방식을 추구함으로써 코드의 복잡성이 증가하고 가독성이 저하되는 문제를 초래할 수도 있으므로 개발자의 숙련도가 요구됩니다.