GoF 디자인 패턴 중 구조에 속해있는 Adapter 패턴에 대해서 다뤄보겠습니다.
구조 패턴이란 클래스나 객체들을 조합해 더 큰 구조로 만들 수 있게 해주는 패턴입니다.
기존 코드를 클라이언트가 사용하는 인터페이스의 구현체로 바꿔주는 패턴입니다.
Client는 인터페이스(프로토콜)를 따르는 코드를 작성했다면 Adaptee에 있는 메서드를 사용하기 위해서는 Client에 있는 코드를 수정해야 합니다. Apdater 패턴을 사용하면 Adaptee를 인터페이스의 구현체로 변경해 사용할 수 있습니다.
패턴 적용 전
protocol LoginService {
func loadUser(userID: String) -> UserInfo
}
protocol UserInfo {
func getUserName() -> String
func getUserPassword() -> String
}
class LoginHandler {
let service: LoginService
init(service: LoginService) {
self.service = service
}
func login(id: String, password: String) throws -> String {
let userDetail = service.loadUser(userID: id)
if userDetail.getUserPassword() == password {
return userDetail.getUserName()
} else {
throw LoginError.defaultError
}
}
}
Client에는 LoginService를 따르는 코드가 작성되어 있습니다.
class Account {
private var id: String = ""
private var password: String = ""
func getID() -> String {
return id
}
func getPassword() -> String {
return password
}
func setPassword(password: String) {
self.password = password
}
func setID(id: String) {
self.id = id
}
}
struct AccountService {
func findAccountUser(userID: String, password: String) -> Account {
let account = Account()
account.setID(id: userID)
account.setPassword(password: password)
return account
}
}
Account와 AccountService를 Client에서 사용하기 위해서는 기존의 코드를 수정해야 하는 불편함이 존재합니다.
패턴 적용
class AccountLoginService: LoginService {
private let service: AccountService
init(service: AccountService) {
self.service = service
}
func loadUser(userID: String) -> UserInfo {
let account = service.findAccountUser(userID: userID, password: "1111")
return AccountInfo(account: account)
}
}
class AccountInfo: UserInfo {
private let account: Account
init(account: Account) {
self.account = account
}
func getUserName() -> String {
return account.getID()
}
func getUserPassword() -> String {
return account.getPassword()
}
}
Target 프로토콜을 준수하는 Adapter 코드를 작성하면 Client는 기존의 코드를 수정하지 않고 Account와 AccountService와 호환해서 사용할 수 있습니다.
Account와 AccountService에서 UserInfo와 LoginService를 직접 채택해서 사용하면 Client의 코드를 수정할 필요 없지 않을까라는 생각을 할 수 있습니다.
- Adaptee나 Target 프로토콜의 코드를 수정할 수 없다면 두 타입을 호환시킬 수 있는 방법은 Adapter 패턴을 적용하는 것입니다.
- 수정이 가능하다면 관리해야 하는 타입이 줄어들지만 기존의 코드를 변경해야 하기 때문에 객체 지향 원칙 중 OCP를 위반하고 과연 해당 타입이 SRP를 준수하는지 고민할 수 있을 것 같습니다.
해당 글은 인프런의 코딩으로 학습하는 GoF 디자인 패턴 강의와 블로그를 참고해 작성했습니다.
참고 자료
Refactoring.Guru
⭐️ 부족하거나 잘못된 부분이 있다면 댓글은 언제나 환영입니다!! ⭐️