ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 헤드 퍼스트 디자인 패턴 - 1장 디자인 패턴의 세계로 떠나기
    도서 2023. 7. 16. 21:54

    디자인 패턴의 세계로 떠나기

    Duck 을 상속하여 여러 종류의 오리를 만들었다

    날기 기능을 추가하고 싶어서 Duck 클래스에 fly() 메소드를 추가한다면?

    날지 않는 오리(장난감 오리)도 날게 되어 버린다.

    • 상속을 활용한다면 규격이 바뀔 때마다 서브 클래스의 메소드를 상황에 따라 오버라이드해야 한다.
    • 상속대신 인터페이스를 구현하는 것으로 바꾼다면 이런 문제는 해결할 수 있다(Flyable, Quackable)
    • 하지만 코드 재사용이 안된다는 점에서 코드 관리에 문제가 발생할 수 있다

    디자인 원칙 1

    • 애플리케이션에서 달라지는 부분을 찾아 달라지지 않는 부분과 분리한다
    • 즉 바뀌는 부분은 따로 뽑아 캡슐화를 하여 바뀌지 않는 부분에 영향을 미치지 않고 고치거나 확장할 수 있게 한다

    오리의 경우

    • 나는 행동
    • 꽥꽥거리는 행동

    이 각 클래스 집합은 최대한 유연하게 만드는 것이 좋다

    그리고 인스턴스를 만들고 특정 형식의 행동으로 초기화하는 방법도 생각해볼 수 있다

    디자인 원칙 2

    • 구현보다는 인터페이스에 맞춰서 프로그래밍한다

    오리의 경우

    각 행동별로 FlyBehavior, QuackBehavior 로 표현하는 인터페이스를 사용하여 구현

    Duck 클래스에서 날기와 꽥꽥을 구현하지 않고 행동 클래스에서 구현

    다른 형식의 객체에서도 나는 행동과 꽥꽥거리는 행동을 재사용할 수 있다

    인터페이스에 맞춰서 → 상위 형식에 맞춰서

    인터페이스를 중의적으로 표현

    • 자바의 구조
    • 인터페이스라는 개념

    반드시 자바의 인터페이스를 사용하라는 것이 아닌 실제 실행시 객체에 코드가 고정되지 않도록 상위 형식(supertype)에 맞춰 프로그램이하여 다형성을 활용

    // 인터페이스나 추상 클래스
    interface Animal {
        fun makeSound()
    }
    
    class Dog: Animal {
        override fun makeSound() {
            bark()
        }
    
        fun bark() { println("멍멍") }
    }
    
    class Cat: Animal {
        override fun makeSound() {
            meow()
        }
    
        fun meow() { println("야옹") }
    }
    
    fun main() {
        val animal = Dog()
        animal.makeSound() // 멍멍

    행동 통합하기

    Duck 클래스에서 직접 구현하지 않고 다른 클래스에 위임하게 된다.

    abstract class Duck {
        protected lateinit var quackBehavior: QuackBehavior
        lateinit var flyBehavior: FlyBehavior
    
        abstract fun display()
    
        fun performQuack() {
            quackBehavior.quack() // quackBehavior 로 위임
        }
    
        fun performFly() {
            flyBehavior.fly()
        }
    
        fun swim() {
            println("오리는 물에 뜬다")
        }
    }
    
    class MallardDuck : Duck() {
    
        init {
            flyBehavior = FlyWithWings()
            quackBehavior = Quack()
        }
    
        override fun display() {
            println("청둥오리")
        }
    }

    캡슐화된 행동 살펴보기

    • 기존의 오리들의 행동을 중심으로 생각하기 → 알고리즘군으로 생각하기
    • 이중 as-a 관계, FlyBehavior 와 QuackBehavior 는 각각 나는 행동과 꽥꽥 거리기를 위임 받음
    • 이렇게 두 클래스를 합치는 것을 구성(composition) 이라고 한다

    디자인 원칙 3

    상속보다는 구성을 활용한다.

    • 시스템의 유연성을 크게 향상 가능
    • 알고리즘군을 별도의 클래스 집합으로 캡슐화
    • 구성 요소인 객체에서 인터페이스를 구현하기만 하면 실행 시에 행동으로 바꿀 수 있음

    전략 패턴

    지금까지 알아본 것이 전략 패턴

    • 알고리즘군을 정의
    • 알고리즘군별 캡슐화하여 각각 수정 가능
    • 클라이언트로부터 알고리즘을 분리하여 독립적 변경 가능

    출처

    도서 - 헤드 퍼스트 디자인 패턴

    코드

    https://github.com/sinna94/head-first-design-patterns

    반응형

    댓글

Designed by Tistory.