SRP(Single Responsibility Principle) 개념
하나의 객체는 하나의 책임을 가져야 한다. 즉 하나의 class가 여러 기능을 담당하면 안된다.
예제코드
class LoginService {
func login(id: String, pw: String) {
let userData = requestLogin()
let user = decodeUserInform(data: userData)
saveUserOnDatabase(user: user)
}
private func requestLogin() -> Data {
// Call API
return Data()
}
private func decodeUserInform(data: Data) -> User {
// Decoding User Inform from Data
return User(name: "", age: 10)
}
private func saveUserOnDatabase(user: User) {
// Save User
}
}
예를 들어 LoginService라는 클래스에서 DB, Decoder, APIHandler의 많은 역할을 중구난방으로 가지고있다.
좋은 예
protocol APIHandlerProtocol{
func requestLogin() -> Data
}
protocol DecodingHandlerProtocol{
func decode<T>(from data: Data) -> T
}
protocol DBHandlerProtorocl{
func saveOnDatabase<T>(inform: T)
}
class LoginService {
let apiHandler: APIHandlerProtocol
let decodingHandler: DecodingHandlerProtocol
let dbHandler: DBHandlerProtorocl
init(apiHandler: APIHandlerProtocol,
decodeingHandler: DecodingHandlerProtocol,
dbHandler: DBHandlerProtorocl){
self.apiHandler = apiHandler
self.decodingHandler = decodeingHandler
self.dbHandler = dbHandler
}
func login(id: String, pw: String) {
let loginData = apiHandler.requestLogin()
let user: User = decodingHandler.decode(from: loginData)
dbHandler.saveOnDatabase(inform: user)
}
}
나쁜 예와 비교하면 각각의 DB, Decoder, APIHandler 역할을 하는 프로토콜을 만들어주고 각자의 역할만 하는 메서드만을 구현하게 했다. 그리고 LoginService에서는 단지 이 프로토콜들을 활용해서 상호작용만을 하고 있다.
이전과 비교해서 확실히 LoginService는 각각의 모듈들을 활용해서 로그인에 관한 책임만을 가지고 있다.
이러한 LoginService클래스를 활용하여 로그인을 수행하는 main함수를 만들 수 있다.
// 사용할 구현체를 만듭니다.
class MyAPIHandler: APIHandlerProtocol {
func requestLogin() -> Data {
// API 요청을 보내고 응답 데이터를 받아온다
return Data()
}
}
class MyDecodingHandler: DecodingHandlerProtocol {
func decode<T>(from data: Data) -> T {
// 데이터를 디코딩하여 사용 가능한 객체로 변환한다.
return data as! T
}
}
class MyDBHandler: DBHandlerProtorocl {
func saveOnDatabase<T>(inform: T) {
// 변환된 객체를 DB에 저장한다.
}
}
func main() {
// 의존성을 주입한다.
let apiHandler = MyAPIHandler()
let decodingHandler = MyDecodingHandler()
let dbHandler = MyDBHandler()
// 의존성을 가지는 인스턴스를 생성한다.
let loginService = LoginService(apiHandler: apiHandler,
decodeingHandler: decodingHandler,
dbHandler: dbHandler)
// 로그인을 시도한다.
loginService.login(id: "my_id", pw: "my_password")
}