책너두 (헤드 퍼스트 디자인 패턴) 3일차 (~55p)

요약

  • 디자인 패턴 소개와 전략 패턴 (계속)
    • 상속을 생각하기
    • 인터페이스 설계하기
    • 해결 방법 고민하기
    • 소프트웨어 개발 불변의 진리
    • 문제를 명확하게 파악하기
    • 바뀌는 부분과 그렇지 않은 부분 분리하기
    • 오리의 행동을 디자인하는 방법
    • 오리의 행동을 구현하는 방법
    • 오리 행동 통합하기

메모

상속을 생각하기

  • 날고, 소리를 내는 오리를 구현하기 위해 상속을 한다면?
    • 나무로된 가짜 오리를 추가해야 한다면..?
    • 날수도 없고 소리를 낼 수도 없다.
    • 그러면 그 서브클래스는 아무것도 하지 않도록 오버라이드를 계속해줘야 함.
  • Duck의 행동을 상속할 때 단점이 될 수 있는 요소
    • 서브클래스에서 코드가 중복된다.
    • 실행 시에 특징을 바꾸기 힘들다.
    • 모든 오리의 행동을 알기 힘들다.
    • 코드를 변경했을 때 다른 오리들에게 원치 않은 영향을 끼칠 수 있다.

인터페이스 설계하기

  • 상속이 옳은 방법이 아니라 판단하고, 인터페이스를 설계함.
    • fly() 메서드를 슈퍼 클래스에서 빼고 Flyable 인터페이스에 만듦.
    • 마찬가지로 quack() 메서드도 Quackable 인터페이스에 만듦.

해결 방법 고민하기

  • 근데 인터페이스 설계 또한 코드 중복이 발생.
    • 메소드 몇 개 오버라이드하기 싫어서 인터페이스를 쓴다고해도 Duck 하위 날아야하는 서브 클래스들은 코드를 전부 바꿔줘야 함.
      • 코드를 재사용하지 않기 때문.
      • 또, 날 수 있는 오리 중, 날아다니는 방식이 다를 수도 있음.

소프트웨어 개발 불변의 진리

  • 소프트웨어 개발에 있어 변화는 항상 있음.
    • ex)
    • 고객이나 사용자가 다른 것을 요구하거나 새로운 기능을 원할 때
    • 회사 데이터베이스 종류와 데이터를 원래 구입하던데와 달리 다른 곳에서 구입했는데, 지금 사용하는 데이터 포맷과 완전히 다를때
    • 기술이 발전하면서 어떤 규약을 사용하려고 코드를 갱신할 때
    • 시스템을 만들면서도 중간중간 배우면서 앞으로 돌아가 더 좋게 고치고 싶을 때
  • 아무리 디자인을 잘한 애플리케이션이라도 시간이 지남에 따라 변화하고 성장해야 함.

문제를 명확하게 파악하기

  • 상속 → 모든 서브클래스에게 한 가지 행동만 사용하도록 하는 건올바르지 못함.
  • 인터페이스 → 구현 코드가 없으므로 코드 재사용할 수 없음.
    • ex) 한가지 행동을 바꿀 때마다 그 행동이 정의되어 있는 서로 다른 서브 클래스를 전부 찾아서 코드를 일일이 고쳐야 함. → 그 과정에서 새로운 버그가 생길 가능성도 있음.
  • 이 상황에 딱 어울릴만한 디자인 원칙이 있음.
📍 첫번째 디자인 원칙 : 애플리케이션에서 달라진 부분을 찾아내고, 달라지지 않는 부분과 분리한다. “바뀌는 부분은 따로 뽑아서 캡슐화한다. 그러면 나중에 바뀌지 않는 부분에는 영향을 미치지 않고 그 부분만 고치거나 확장할 수 있다.”

바뀌는 부분과 그렇지 않은 부분 분리하기

  • 변화하는 부분을 뽑아낸다.
  • Duck 클래스와 별개로, 2개의 클래스 집합(set)을 만들어야 함.
    1. 나는 것과 관련된 부분
    2. 꽥꽥거리는 것과 관련된 부분
    • 각 클래스 집합에 각 행동을 구현한 것을 전부 집어넣음.
      • ex) 꽥꽥 거리는 행동을 구현하는 클래스 / 뺵빽 거리는 행동을 구현하는 클래스 / 아무 소리도 내지 않는 행동을 구현하는 클래스

오리의 행동을 디자인하는 방법

  • Duck의 인스턴스에 오리 행동을 할당할 수 있어야 함.
    • ex) MallardDuck 인스턴스는 특정 형식의 나는 행동으로 초기화할 수 있어야 함.
  • 오리 행동을 동적으로 바꿀 수 있으면 더 좋음.
    • ex) Duck 클래스에 행동과 관련된 세터 메소드를 포함해서 프로그램 실행 중에도 MallardDuck의 나는 행동을 바꿀 수 있게 함.
📍 두번째 디자인 원칙 : 구현보다는 인터페이스에 맞춰서 프로그래밍한다. ”인터페이스에 맞춰서 프로그래밍한다”라는 말은 사실 “상위 형식에 맞춰서 프로그래밍한다” 라는 말임.
  • FlyBehavior, QuackBehavior 인터페이스를 사용해서 행동을 구현함.
    • 더이상 Duck 클래스에서 구현하지 않음.
    • 대신, 특정 행동만을 목적으로 하는 클래스 집합을 만듦. (ex: 삑삑 소리내기 행동)
  • 이러한 디자인을 사용하면 Duck 서브클래스는 인터페이스로 표현되는 행동을 사용함.
    • 구현 클래스는 Duck 서브클래스와 독립적임.

오리의 행동을 구현하는 방법

  • FlyBehavior 인터페이스
    • FlyWithWings 구현체
    • FlyNoWay 구현체
  • QuackBehavior 인터페이스
    • Quack 구현체
    • Squeak 구현체
    • MuteQuack 구현체
  • 이런식으로 디자인하면 더이상 Duck 클래스 안에 행동이 숨겨져 있지 않으므로 행동을 재사용할 수 있음.

오리 행동 통합하기

  • 나는 행동과 꽥꽥거리는 행동을 Duck 클래스에서 정의한 메서드를 써서 구현하지 않고, 다른 클래스에 위임함.
    • 인터페이스를 만들어서 클래스 집합을 만들었음.
    • 이렇게 행동에 대한 클래스집합을 분리했기 때문에 Duck의 서브 클래스가 인스턴스화 될 때 특정 행동에 대한 구현체만 다형성을 이용해서 인터페이스에 셋팅해주면 됨.
    • 이때, 인터페이스를 Duck 이 인스턴스 변수로 사용하고 있기 때문에 프로그램 실행 시에 동적으로 행동을 변경할 수 있음.

댓글

Designed by JB FACTORY