SOLID란
- 객체지향 설계에 더 좋은 아키텍쳐를 설계하기 위해 지켜야하는 원칙들의 5가지를 앞의 약어만 따서 정리한 단어
- 디자인 패턴 중, VIPER, MVVM들도 모두 이런 원칙에 입각하여 만들어진 패턴이다
- SRP(Single Responsibility Principle) - 단일 책임 원칙
클래스나 함수를 설계할 때, 각 단위들은 단 하나의 책임만을 가져야한다는 원칙
클래스나 함수가 새롭게 변해야 한다면 하나의 역할을 가진 상태에서 새로운 것으로 변해야한다는 것(즉, 하나의 일만하고 변해도 하나의 일만 해야 한다)
예제 코드
// SRP( Single Responsibility Priciple) - 단일 책임 원칙
// API, Database, Decoding (Bad Case)
class LoginServiceBad {
func login(id: String, pw: String) {
let userData = requestlogin()
let user = decodeUserInfom(data: userData)
saveUserOnDatabase(user: user)
}
private func requestlogin() -> Data {
return Data()
}
private func decodeUserInfom(data: Data) -> User {
return User(name: "testUser", age: 10)
}
private func saveUserOnDatabase(user: User) {
print("User data \(user.name) are saved!!!")
}
}
class User {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
private func toString() {
print("My Name is: \(self.name), and \(self.age) years old")
}
}
- LoginService 클래스가 API request, Data decoding, Database control 3가지의 기능을 모두 구현하고 있어 SRP 원칙에 어긋나게 된다
// use Protocols to
protocol APIHanlderProtocol {
func requestLogin() -> Data
}
protocol DecodingHandlerProtocol {
func decode<T>(from data: Data) -> T
}
protocol DatabaseHandlerProtocol {
func saveOnDatabase<T>(inform: T)
}
class LoginServiceNice {
let apiHandler: APIHanlderProtocol
let decodingHandler: DecodingHandlerProtocol
let databaseHandler: DatabaseHandlerProtocol
init(
apiHandler: APIHanlderProtocol,
decodingHandler: DecodingHandlerProtocol,
databaseHandler: DatabaseHandlerProtocol
) {
self.apiHandler = apiHandler
self.decodingHandler = decodingHandler
self.databaseHandler = databaseHandler
}
func login() {
let loginData = apiHandler.requestLogin()
let user: User = decodingHandler.decode(from: loginData)
databaseHandler.saveOnDatabase(inform: user)
}
}
class RequestManager: APIHanlderProtocol {
func requestLogin() -> Data {
return Data()
}
}
class DecodingManager: DecodingHandlerProtocol {
func decode<T>(from data: Data) -> T {
return User(name: "testUserName", age: 20) as! T
}
}
class DatabaseManager: DatabaseHandlerProtocol {
func saveOnDatabase<T>(inform: T) {
print("Database completed Save process")
}
}
let loginServiceNice = LoginServiceNice(
apiHandler: RequestManager(),
decodingHandler: DecodingManager(),
databaseHandler: DatabaseManager()
)
loginServiceNice.login()
- LoginSerice 클래스는 정말 로그인 관련된 내용만 구현하게 하고 API, Decoding, Database 는 각각의 핸들러를 만들어 외부에서 주입 받아 SRP 원칙을 따르도록 변경하여 처리한다