소프트웨어 설계에서 반복적으로 발생하는 문제에 대해 반복적으로 적용할 수 있는 해결 방법을
디자인 패턴이라고 부른다. 디자인 패턴이 설계를 재사용하기 위한 것이라면 프레임워크는 설계와 코드를 함께 재사용하기 위한 것이다. 프레임워크는 애플리케이션의 아키텍처를 코드 형태로
제공한다.
디자인 패턴은 특정 변경을 일관성 있게 다룰 수 있는 협력 템플릿을 제공한다. 프레임워크는 특정 변경을 일관성 있게 다룰 수 있는 확장 가능한 코드 템플릿을 제공한다. 결론적으로 디자인 패턴과 프레임워크 모두 협력을 일관성 있게 만들기 위한 방법이다.
패턴이란 무엇인가를 논의할 때 반복적으로 언급되는 몇 핵심적인 특징이 있다.
패턴은 한 컨텍스트에서 유용한 동시에 다른 컨텍스트에서도 유용한 ‘아이디어’다. 패턴은 실무에서 검증된 경험의 산물로, 커뮤니티가 문제의 해결책을 단순한 언어로 다룰 수 있도록 돕는다.
가장 일반적으로 패턴은 범위, 적용 단계에 따라 아키텍처 패턴, 분석 패턴, 디자인 패턴, 이디엄의
4가지로 분류한다. 디자인 패턴은 특정 정황 내에서 일반적인 설계 문제를 해결하며, 협력하는
컴포넌트들 사이에서 반복적으로 발생하는 구조를 서술한다. 이는 언어나 프로그래밍 패러다임에
독립적이다.
아키텍처 패턴은 소프트웨어의 전체 구조를 결정하기 위해 사용하며 미리 정의된 서브 시스템들을 제공, 각 서브시스템들의 책임을 정의한다.
이디엄은 디자인 패턴의 하위에 위치하며, 특정 프로그래밍 언어에만 국한된 하위 레벨 패턴으로
주어진 언어의 기능을 사용해 컴포넌트, 혹은 컴포넌트 간의 특정 측면을 구현하는 방법을 서술한다.
앞선 패턴들이 주로 기술적 문제를 해결하는 데 초점을 두고 있다면 분석 패턴은 도메인 내의
개념적인 문제를 해결하는 데 중점을 둔다. 업무 모델링 시에 발견되는 공통 구조를 표현하는
개념들의 집합이다.
패턴은 공통으로 사용할 수 있는 역할, 책임, 협력의 템플릿이다.
중요한 것은 패턴을 따르면 특정 상황에 적용할 수 있는 설계를 빠르고 쉽게 떠올릴 수 있다는
것이다. 적용 가능한 패턴을 안다면 책임 주도 설계의 절차를 따르지 않더라도 역할, 책임, 협력
관계를 빠르고 쉽게 구성할 수 있다.
패턴의 구성 요소는 클래스가 아니라 ‘역할’이다. 패턴을 구성하는 요소가 클래스가 아니라
역할이라는 사실은 패턴 템플릿을 구현할 수 있는 다양한 방법이 존재한다는 사실을 암시한다.

앞서 살펴보았던 중복 할인 설계의 기본 구조가 COMPOSITE 패턴을 따른다.

몇 이례적인 경우를 제외하면 알려진 대부분의 디자인 패턴은 협력을 일관성 있고 유연하게 만드는 것을 목적으로 한다. 각 디자인 패턴은 특정 변경을 캡슐화하기 위한 독자적인 방법을 정의하고 있다.
영화 예매 시스템에서 Movie 와 DiscountPoilcy 는 STRATEGY 패턴을 이용하여 알고리즘의 변경을 캡슐화한 예시다.

Moive 와 그 Movie 를 상속 받아 calculateDiscountAmount 메서드를 구현한 설계는 TEMPLATE METHOD 패턴을 이용하여 알고리즘을 상속을 통해 캡슐화한 예시다.
한편, 핸드폰 과금 시스템 설계는 DECORATOR 패턴을 기반으로 한다. 이 패턴은 객체의 행동을
동적으로 추가할 수 있게 해주는 패턴으로 기본적으로 객체의 행동을 결합하기 위해 객체 합성을
사용한다. 이를 통해 선택적인 행동의 개수와 순서에 대한 변경을 캡슐화할 수 있다.

패턴은 출발점이지 목적지가 아니다. 패턴을 맹목적으로 그대로 따르지 말고 목적에 맞게
수정하여야 한다. 패턴에 처음 입문한 사람들은 아무리 사소한 설계라도 패턴을 적용해보려
시도한다. 하지만 명확한 트레이드오프 없이 패턴을 남용하면 불필요하게 복잡해지게 된다.
재사용 관점에서 설계 재사용보다 더 좋은 방법은 코드 재사용이다. 하지만 컴포넌트 기반의 재사용 방법이라는 아이디어는 이상적이지만 실제 적용 과정에서 현실적이지 않다는 사실이 밝혀졌다.
가장 좋은 방법은 설계 재사용과 코드 재사용을 적절한 수준으로 조합하는 것이다. 이에 제시된
방법이 바로 프레임워크 다.
프레임워크란 ‘추상 클래스, 인터페이스를 정의하고 인스턴스 사이의 상호작용을 통해 시스템 전체 혹은 일부를 구현해 놓은 재사용 가능한 설계’ 또는 ‘애플리케이션 개발자가 현재
요구사항에 맞게 커스터마이징할 수 있는 애플리케이션의 골격’을 의미한다.
프레임워크는 코드를 재사용함으로써 설계 아이디어를 제공한다.
프레임워크의 핵심은 추상 클래스나 인터페이스와 같은 추상화라고 할 수 있다. 전통적인
소프트웨어 개발 방법의 경우 상위 모듈이 하위 모듈에, 구체적인 세부 사항에 의존하도록
소프트웨어를 구성했다. 하지만 상위 정책과 세부 사항이 변경에 영향을 받는 정도가 다르다. 따라서 이러한 의존 관계는 변경의 파급 효과로 인해 상위 정책을 불안정하게 만든다.
요점은 상위 정책이 세부 사항보다 더 다양한 상황에 사용될 수 있어야 한다는 것이다. 따라서 DIP에 맞게 상위 정책과 세부 사항 모두 추상화에 의존하게 만드는 것이 좋은 방법이다. 프레임워크는 여러 애플리케이션에 걸쳐 재사용 가능해야 하기 때문에 변하는 것과 변하지 않는 것들을 서로 다른
주기로 배포할 수 있도록 별도의 ‘배포 단위’로 분리해야 한다.

중요한 것은 패키지 사이 의존성 방향으로, DIP에 따라 추상화에만 의존하도록 세부 사항을 구현한 패키지는 항상 상위 정책을 구현한 패키지에 의존해야 한다.
상위 정책을 재사용한다는 것은 결국 도메인에 존재하는 핵심 개념들 사이의 협력 관계를
재사용한다는 것을 의미한다. OOP 설계의 재사용성은 객체들 사이의 공통적인 협력 흐름으로부터 나오고, 이는 DIP를 기반으로 한다. 한편, DIP는 제어 흐름의 주체 역시 역전시킨다.
프레임워크가 애플리케이션에 속하는 서브클래스의 메서드를 호출하기 때문에 프레임워크 사용시 개별 애플리케이션에서 프레임워크로 제어 흐름의 주체가 이동한다. 이를 제어 역전 원리 또는
할리우드 원리라고 부른다.특정 기본 정책을 구현하는 개발자는 서브타입만 개발하면 프레임워크에 정의된 플로우에 따라 작업이 수행된다.
프레임워크에서는 일반적인 해결책만 제공하고 애플리케이션에 따라 달라질 수 있는 특정 동작은 비워둔다. 이렇게 완성되지 않은 동작을 훅이라고 부른다. 훅의 구현 방식은 애플리케이션의
컨텍스트에 따라 달라진다. 재정의된 훅은 제어 역전 원리에 따라 프레임워크가 원하는 시점에
호출한다. 여기서 협력 제어 주체는 프레임워크다. 우리의 코드는 수동적인 존재다.
이러한 제어의 역전이 프레임워크의 핵심 개념인 동시에 코드 재사용의 가능하게 하는 힘이다.