헤드 퍼스트 디자인 패턴 - 7장 어댑터 패턴과 퍼사드 패턴 in Swift

koi·2022년 11월 6일
0
post-thumbnail

책이 너무 재밌게 쓰여있어서 개인적으로 즐겁게 정리한 챕터였습니당..😚
어댑터 패턴부터 시작해볼게요!


◽️ 어댑터 패턴

국산 전원 플러그를 유럽식 소켓에 꽂을 수 있게 해 주는 역할을 하는 것이 우리 일상생활에서 쓰이는 어댑터이다.

객체지향에서의 어댑터도 일상 생활에서 쓰이는 어댑터와 똑같은 역할을 한다.

어떤 인터페이스를 클라이언트에서 요구하는 형태의 인터페이스에 적응 시켜주는 역할을 한다.

🔌 어댑터 패턴이란?
한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환한다.
어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다.


👀 기존 시스템에 새로운 인터페이스를 쓸 일이 생겼다..!

어떤 소프트웨어 시스템이 있는데, 새로운 업체에서 제공한 클래스 라이브러리를 사용해야 한다.그런데 새로 채택한 업체에서 사용하는 인터페이스가 기존 업체에서 사용하던 인터페이스와 다르면 어떻게 될까?

그럼.. 이제 모든 코드를 새로운 인터페이스를 사용할 수 있도록 일일이 변경해야할까..?


놉!!

이렇게 어댑터를 사용해서 클라이언트에서 원하는 인터페이스로 변환시켜주면 기존 시스템의 코드는 물론이고 업체에서 제공한 새로운 클래스도 전혀 수정할 일이 없다.

그저 어댑터 부분을 추가하기만 하면 된다.
어댑터에도 객체지향 어댑터클래스 어댑터 두가지 종류가 있다.

객체 어댑터

객체지향 어댑터는 Client, Target, Adapter, Adaptee로 구성되어있다.

  • Client 기존 비즈니스 로직을 포함하는 클래스
  • Target Interface Client 코드에 드러날 Adapter의 기능
  • Adapter Client와 Adapter 모두와 함께 일할 수 있는 클래스, Adaptee 객체를 wrapping 해서 Client 인터페이스를 구현
  • Adaptee Client와 호환되지 않는 인터페이스인 직접 사용할 수 없는 클래스

클래스 어댑터

구성을 통해 어댑티에 요청을 전달하는 객체 어댑터와 다르게
클래스 어댑터에서 어댑터는 타겟과 어댑티의 서브클래스로 구현한다.

그러나 자바, swift 등에서는 다중 상속을 지원하지 않기 때문에 이를 구현할 수 없다.

객체 어댑터와 클래스 어댑터 차이점

  • 객체 어댑터는 어댑티의 서브 클래스에 대해서도 어댑터 역할을 할 수 있다.
  • 클래스 어댑터는 특정 어댑티 클래스에만 적용된다.
    대신 서브클래스기 때문에 어댑티의 행동을 오버라이드할 수 있다는 것이 장점이다.
  • 클래스 어댑터는 어댑터 코드에 어떤 행동을 추가하면 어댑티 클래스 뿐만 아니라 모든 서브 클래스에 대해서도 그대로 적용된다.

어댑터 패턴 in Swift

아래 예시 통해서 어떻게 Adapter Pattern이 다음과 같이 기존 기능에 외부 라이브러리를 추가해서 적용하는지 살펴보자!

자체 로그인 기능만 있던 서비스에 Apple 아이디로 로그인하기, Google 아이디로 로그인하기 등등 다른 플랫폼 로그인 정보를 이용해서 인증을 거치는 기능을 추가하려고 한다.

  • 기존 로그인 시스템의 login()을 타겟 인터페이스로 분리하고
  • 기존 로그인 시스템은 타겟 인터페이스를 프로토콜을 채택하되 내부 구현 내용은 수정하지 않아도 된다.
  • 애플 로그인, 구글 로그인이 인터페이스를 구현하도록 한다.
    내부에서는 어댑티를 통해 로그인을 구현한다.

그러면 기존 구현을 수정하지 않고도 로그인을 플랫폼별로 실행할 수 있게 된다!


데코레이터와 어댑터의 차이점

객체를 한번 감싼다는 것에 공통점을 가지고 있는 두 패턴 데코레이터와 어댑터가 팽팽하게 싸우고 있다...

🎁 우린 새로운 책임 또는 행동을 디자인에 추가해줘
🔌 우린 열심히 인터페이스를 변환해줘
🎁 우리도 열심히 일하거든? 커다란 인터페이스를 장식할 땐 코드가 엄청 많이 필요해
🔌 우리도 여러 클래스를 클라이언트가 원하는 인터페이스에 맞게 변환하려면 힘들어
🎁 우리도 데코레이터가 겹겹이 싸여있을 때도 있어. 그러면 얼마나 많은 다른 데코레이터를 거쳐왔는지도 알 수 없지..
🔌 우린 어댑터에서 어떤 일을 해도 클라이언트는 우리가 거기 있었다는 사실 조차 몰라줘..
🔌 그래도 우리 덕분에 클라이언트들은 기존 코드를 하나도 안고치고 새로운 라이브러리를 쓸 수 있지
🎁 우리도 비슷해. 기존 코드를 고치지 않고도 클래스에 새로운 행동을 추가할 수 있거든.


🎁 그런데 너넨 그냥 메소드 호출을 통과시키는 역할을 하는 데코레이터 아냐??
🔌 뭔 소리여. 우린 언제나 우리가 감싸고 있는 인터페이스를 변환해줘. 너네가 일종의 어댑터겠지!


결론

  • 데코레이터인터페이스를 바꾸지 않고 책임(기능)만 추가한다.
  • 어댑터는 인터페이스를 변경해서 클라이언트에서 필요로 하는 인터페이스로 적응시키기 위한 용도로써 호환성을 위해 사용한다.

어댑터 패턴의 장단점

  • 👍 장점
    • Adaptee의 기능과 Adapter의 동작을 비즈니스 로직과 분리 할 수 있기 때문에 SRP 단일 책임 원칙을 지킬 수 있다.
    • 어댑터를 통해 작업하면 Client 인터페이스를 통해서만 작업할 수 있고, 새로운 어댑터를 추가할 수 있기 때문에 OCP 개방/폐쇄 원칙을 지킬 수 있다.
  • 👎 단점
    • 복잡성 증가: 새로운 인터페이스나 클래스를 추가하다보니 전체 코드의 복잡성이 증가할 수 있다.
      → Adaptee 를 extension 하거나 변경하는게 더 간단할 수 있음

◽️ 퍼사드 패턴

Facade는 프랑스어 Façade에서 유래된 단어로 건물의 출입구로 이용되는 정면 외벽 부분을 가리키는 말로 '건물의 정면'을 의미한다.

즉 퍼사드 패턴은 건물 내부를 감싼 외벽처럼, 복잡한 서브 시스템을 간단한 인터페이스로 감싸서 사용하기 쉽게 만드는 것이다.

🏢 퍼사드 패턴이란?
어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인퍼테이스를 제공한다.
퍼사드에서 고수준 인터페이스를 정의하기 때문에 서브시스템을 더 쉽게 사용할 수 있다.


퍼사드 패턴 in Swift

protocol Facade {
    func work()
}

struct CPU {
    func work(with memory: Memory) { }
}

struct Memory {
    func input(from Devices: [Device]) { }
    func output(to Devices: [Device]) { }
}

class Device { ... }
class InputDevice: Device { ... }
class OutputDevice: Device { ... }
class Keyboard: InputDevice { ... }
class Monitor: OutputDevice { ... }
class TouchBar: Device { ... }

struct Computer: Facade {
    private let cpu = CPU()
    private let memory = Memory()
    private let keyboard = Keyboard()
    private let monitor = Monitor()
    private let touchBar = TouchBar()

    func work() {
        memory.input(from: [keyboard, touchBar])
        cpu.work(with: memory)
        memory.output(to: [monitor, touchBar])
    }
}

// My code
let computer = Computer()
computer.work()

퍼사드 패턴의 장단점

  • 👍 장점
    • 서브 시스템의 복잡성으로부터 코드를 분리할 수 있다.
    • 서브 시스템으로부터 클라이언트를 보호하고 클라이언트가 서브 시스템을 사 용하기 쉽게 만들어준다.
    • Facade를 사용하여 시스템과 객체 간 종속성을 계층화할 수 있다.
    • 컴파일 종속성을 줄여 서브 시스템이 변경될 때 컴파일 시간을 줄여준다.
  • 👎 단점
    • Facade는 앱의 모든 클래스에 결합된 객체가 될 수 있다.

참고

swift 구현 예시는 야곰닷넷을 참고했습니다!

profile
Don't think, just do 🎸

0개의 댓글