01. 전략 패턴 - 디자인 패턴 소개

솔트커피·2022년 7월 11일
0

바뀌는 부분과 그렇지 않은 부분 분리하기 (46p)

디자인 원칙 - 애플리케이션에서 달라지는 부분을 찾아내고 달라지지 않는 부분과 분리한다.

'변화하는 부분과 그대로 있는 부분'을 분리하려면 2개의 클래스 집합을 만들어야 합니다.

각 클래스 집합에는 각각의 행동을 구현한 것을 전부 집어 넣습니다.

fly()와 quack()은 Duck 클래스에 있는 오리 종류에 따라 달라지는 부분입니다.

fly()와 quack()을 Duck 클래스로부터 분리하려면 2개의 메소드를 모두 Duck 클래스에서 끄집어 내서 각 행동을 나타낼 클래스 집합을 새로 만들어야 합니다.

오리의 행동을 디자인하는 방법 (47p)

나는 행동과 꽥꽥거리는 행동을 구현하는 클래스 집합은 어떻게 디자인해야 할까요?

우선 최대한 유연하게 만드는 것이 좋겠죠? 애초에 이런 문제에 말려든게 오리의 행동과 관련된 유연성 때문이었으니까요.

예를 들어 MallardDuck 인스턴스를 새로 만들고 특정 형식의 나는 행동으로 초기화하는 방법도 생각해 볼 수 있습니다.

오리의 행동을 동적으로 바꿀 수 있으면 좋겠죠? 즉, Duck 클래스에 행동과 관련도니 setter 메소드를 포함해서 프로그램 실행 중에도 MallardDuck의 나는 행동을 바꿀 수 있으면 좋겠습니다.

일단 이렇게 목표를 정해 놓고 두 번째 디자인 원칙을 살펴봅시다.

디자인 원칙 - 구현보다는 인터페이스에 맞춰서 프로그래밍 한다.

각 행동은 인터페이스(FlyBehavior, QuackBehavior)로 표현하고 인터페이스를 사용해서 행동을 구현하겠습니다.

나는 행동과 꽥꽥거리는 행동은 이제 Duck 클래스에서 구현하지 않습니다.

대신 특정 행동('삑삑 소리 내기'와 같은 행동)만을 목적으로 하는 클래스의 집합을 만들겠습니다.

행동(behavior) 인터페이스는 Duck 클래스가 아니라 방금 설명한 행동 클래스에서 구현합니다.

이 방법은 지금까지 썼던 행동을 Duck 클래스에서 구체적으로 구현하거나 서브클래스 자체에서 별도로 구현하는 방법과는 상반된 방법입니다.

전에 썼던 방법은 항상 특정 구현에 의존했기 때문에 (코드를 추가하지 않는 이상) 행동을 변경할 여지가 없었죠.

새로운 디자인을 사용하면 Duck 서브 클래스는 인터페이스로 표현되는 행동을 사용합니다.

따라서 실제 행동 구현(즉 FlyBehavior나 QuackBehavior를 구현하는 클래스에 코딩되어 있는 구체적인 특정 행동)은 Duck 서브클래스에 국한되지 않습니다.

"인터페이스에 맞춰서 프로그래밍한다"라는 말은 사실 "상위 형식에 맞춰서 프로그래밍한다"는 말입니다.

인터페이스에 맞춰서 프로그래밍하라고 했다고 반드시 자바의 인터페이스를 사용하라는 뜻은 아닙니다.

핵심은 실제 실행 시에 쓰이는 객체가 코드에 고정되지 않도록 상위 형식(supertype)에 맞춰 프로그래밍 해서 다형성을 활용해야 한다는 점에 있습니다.

"상위 형식에 맞춰서 프로그래밍하라"는 원칙은 "변수를 선언할 때 보통 추상 클래스나 인터페이스 같은 상위 형식으로 선언해야 한다.

객체를 변수에 대입할 때 상위 형식을 구체적으로 구현한 형식이라면 어떤 객체든 넣을 수 있기 때문이다.

그러면 변수를 선언하는 클래스에서 실제 객체의 형식을 몰라도 된다"라는 뜻으로 생각하면 됩니다.

오리 행동 통합하기 (51p)

가장 중요한 점은 나는 행동과 꽥꽥거리는 행동을 Duck 클래스(또는 그 서브클래스)에서 정의한 메소드를 써서 구현하지 않고 다른 클래스에 위임한다는 것입니다.

캡슐화된 행동 살펴보기 (58p)

이번에는 생각하는 방식을 조금 바꿔 봤습니다. 오리의 행동들을 일련의 행동을 생각하는 대신, 알고리즘군(family of algorithms)으로 생각하는 거죠.

SimUDuck 디자인에서 알고리즘은 오리가 하는 행동(다른 방식으로 꽥꽥거리고 나는 행동)을 나타내지만, 지역에 따라 달라지는 세금 계산 방식을 구현하는 클래스에도 활용할 수 있습니다.

클래스 다이어그램에 있는 각 화살표와 클래스들이 어떤 관계인지("A는 B이다" 관계인지, "A에는 B가 있다" 관계인지, 아니면 "A가 B를 구현하는" 관계인지) 직접 연필로 써 보세요.

두 클래스를 합치는 방법 (59p)

"A에는 B가 있다" 관계를 생각해 봅시다.

각 오리에는 FlyBehavior와 QuackBehavior가 있으며, 각각 나는 행동과 꽥꽥거리는 행동을 위임받습니다.

이런 식으로 두 클래스를 합치는 것을 '구성(Composition)을 이용한다'라고 부릅니다.

여기에 나와 있는 오리 클래스에서는 행동을 상속받는 대신, 올바른 행동 객체로 구성되어 행동을 부여 받습니다.

구성은 매우 중요한 테크닉이자 세 번째 디자인 원칙이기도 합니다.

디자인 원칙 - 상속보다는 구성을 활용한다.

핵심 정리

  • 객체지향 기초
    • 추상화
    • 캡슐화
    • 다형성
    • 상속
  • 객체지향 원칙
    • 바뀌는 부분은 캡슐화한다.
    • 상속보다는 구성을 활용한다.
    • 구현보다는 인터페이스에 맞춰서 프로그래밍하낟.
  • 객체지향 패턴 - 전략 패턴
    • 전략 패턴은 알고리즘군을 정의하고 캡슐화해서 각각의 알고리즘군을 수정해서 쓸 수 있게 해 줍니다.
    • 전략 패턴을 사용하면 클라이언트로부터 알고리즘을 분리해서 독립적으로 변경할 수 있습니다.
  • 훌륭한 객체지향 디자인이라면 재사용성, 확장성, 관리의 용이성을 갖출 줄 알아야합니다.
  • 패턴은 훌륭한 객체지향 디자인 품질을 갖추고 있는 시스템을 만드는 방법을 제공합니다.
  • 패턴은 검증받은 객체지향 경험의 산물입니다.
  • 대부분의 패턴과 원칙은 소프트웨어의 변경 문제와 연관되어 있습니다.
  • 대부분의 패턴은 시스템의 일부분을 나머지 부분과 무관하게 변경하는 방법을 제공합니다.
  • 많은 경우에 시스템에서 바뀌는 부분을 골라내서 캡슐화해야 합니다.
  • 패턴은 다른 개발자와의 의사소통을 극대화하는 전문 용어 역할을 합니다.

0개의 댓글