본문 바로가기

기술서적 정리/오브젝트 - 코드로 이해하는 객체지향 설계

15 CHAPTER 디자인 패턴과 프레임워크

https://wikibook.co.kr/object/

 

오브젝트: 코드로 이해하는 객체지향 설계

역할, 책임, 협력을 향해 객체지향적으로 프로그래밍하라! 객체지향으로 향하는 첫걸음은 클래스가 아니라 객체를 바라보는 것에서부터 시작한다. 객체지향으로 향하는 두 번째 걸음은 객체를

wikibook.co.kr

 

 

디자인 패턴을 익히고 나면 변경의 방향과 주기를 이해하는 것만으로도 필요한 역할과 책임, 역할들의 협력 방식을 순간적으로 떠올릴 수 있게 된다.

 

디자인 패턴이 설계를 재사용하기 위한 것이라면 프레임워크는 설계와 코드를 함께 재사용하기 위한 것이다.

프레임워크는 애플리케이션의 아키텍처를 구현 코드의 형태로 제공한다.

프레임워크는 각 애플리케이션 요구에 따라 적절하게 커스터마이징할 수 있는 확장 포인트를 제공한다.

 

디자인 패턴이 협력을 일관성 있게 만들기 위해 재사용할 수 있는 설계의 묶음이라면, 프레임워크는 일관성 있는 협력을 제공하는 확장 가능한 코드라고 할 수 있다.

결론적으로 디자인 패턴과 프레임워크 모두 협력을 일관성 있게 만들기 위한 방법이다.

 

 

◈ 디자인 패턴과 설계 재사용

패턴과 책임-주도 설계

스트래티지 패턴은 다양한 알고리즘을 동적으로 교체할 수 있는 역할과 책임의 집합을 제공한다.

객체들이 할 수 있는 행위 각각에 대해 전략 클래스를 생성하고, 유사한 행위들을 캡슐화 하는 인터페이스를 정의한다.

그리고 객체의 행위를 동적으로 바꾸고 싶은 경우 직접 행위를 수정하지 않고 전략을 바꿔주기만 함으로써 행위를 유연하게 확장하는 방법이다.

 

브릿지 패턴은 추상화의 조합으로 인한 클래스의 폭발적인 증가 문제를 해결하기 위해 역할과 책임을 추상화와 구현의 두 개의 커다란 집합으로 분해함으로써 설계를 확장 가능하게 만든다.

 

옵저버 패턴은 유연한 통지 메커니즘을 구축하기 위해 객체 간의 결합도를 낮출 수 있는 역할과 책임의 집합을 제공한다.

옵저버 패턴은 어떤 객체의 상태가 변할 때 그와 연관된 객체 들에게 알림을 보내는 디자인 패턴이다.

 

컴포지트 패턴여러 개의 객체들로 구성된 복합 객체와 단일 객체를 클라이언트에서 구별 없이 다루게 해주는 패턴이다.

컴포지트 패턴은 개별 객체와 복합 객체라는 객체의 수와 관련된 변경을 캡슐화하는 것이 목적이다.

중복 할인 설계의 기본 구조는 컴포지트 패턴을 따른다.

 

패턴의 구성 요소는 클래스가 아니라 ‘역할’이다.

 

어떤 구현 코드가 어떤 디자인 패턴을 따른다고 이야기할 때는 역할, 책임, 협력의 관점에서 유사성을 공유한다는 것이지 특정한 구현 방식을 강제하는 것은 아니라는 점을 이해하는 것이 중요하다.

 

디자인 패턴은 단지 역할과 책임, 협력의 템플릿을 제안할 뿐 구체적인 구현 방법에 대해서는 제한을 두지 않는다.

 


캡슐화와 디자인 패턴

스트래티지 패턴의 목적은 알고리즘의 변경을 캡슐화하는 것이고 이를 구현하기 위해 객체 합성을 이용한다.

 

알고리즘을 캡슐화하기 위해 합성 관계가 아닌 상속 관계를 사용하는 것을 템플릿 메서드 패턴이라고 부른다.

 

추상 클래스나 인터페이스를 사용해 변경을 캡슐화하는 합성과 달리 상속을 사용할 경우에는 추상 메서드를 이용해 변경을 캡슐화해야 한다.

그리고 자식 클래스들이 이 추상 메서드를 오버라이딩해서 벽하는 부분을 구현하는 것이 중요하다.

 

템플릿 메서드 패턴은 부모 클래스가 알고리즘의 기본 구조를 정의하고 구체적인 단계는 자식 클래스에서 정의하게 함으로써 변경을 캡슐화할 수 있는 디자인 패턴이다.

다만 합성보다는 결합도가 높은 상속을 사용했기 때문에 스트래티지 패턴처럼 런타임에 객채의 알고리즘을 변경하는 것은 불가능하다.

하지만 알고리즘 교체와 같은 요구사항이 없다면 상대적으로 스트래티지 패턴보다 복잡도를 낮출 수 있다는 면에서는 장점이라고 할 수 있다.

 

데코레이터 패턴객체의 행동을 동적으로 추가할 수 있게 해주는 패턴으로서 기본적으로 객체의 행동을 결합하기 위해 객체 합성을 사용한다.

데코레이터 패턴은 선택적인 행동의 개수와 순서에 대한 변경을 캡슐화할 수 있다.

 

어떤 디자인 패턴이 어떤 변경을 캡슐화하는지를 이해하는 것이 중요하다.

그리고 각 디자인 패턴이 변경을 캡슐화하기 위해 어떤 방법을 사용하는지를 이해하는 것이 더 중요하다.

 

 

 

 

◈ 프레임워크와 코드 재사용

코드 재사용 대 설계 재사용

프레임워크란. 

1. 추상 클래스나 인터페이스를 정의하고 인스턴스 사이의 상호작용을 통해 시스템 전체 혹은 일부를 구현해 놓은 재사용 가능한 설계.

또는.

2. 애플리케이션 개발자가 현재의 요구사항에 맞게 커스터마이징을 할 수 있는 애플리케이션의 골격.

이렇게 정의 내릴 수 있다.

 

첫 번째 정의가 프레임 워크의 구조적인 측면에서 초점을 맞추고 있다면, 두 번째 정의는 코드와 설계의 재사용이라는 프레임워크의 사용 목적에 초점을 맞춘다.

 


상위 정책과 하위 정책으로 패키지 분리하기.

상위 정책은 상대적으로 변경에 안정적이기에 상위 정책이 세부 사항보다 더 다양한 상황에서 재사용될 수 있어야 한다.

 

하지만 상위 정책이 세부 사항에 의존하게 되면 상위 정책이 필요한 모든 경우에 세부 사항도 항상 함께 존재해야 하기 때문에 상위 정책의 재사용성이 낮아진다.

이 문제를 해결할 수 있는 가장 좋은 방법은 의존성 역전 원칙에 맞게 상위 정책과 세부 사항 모두 추상화에 의존하게 만드는 것이다.

 

프레임워크는 여러 애플리케이션에 걸쳐 일관성 있는 협력을 구현할 수 있게 해준다.

우리는 동일한 프레임워크를 사용하는 여러 애플리케이션에 걸쳐 일관성 있게 코드를 설계하고 구현할 수 있다.

동일한 프레임워크를 사용하는 애플리케이션은 구현 방식에 일관성이 있기 때문에 이해하기도 쉽다.

추가적으로 설계와 함께 코드 역시 재사용할 수 있다.

 


제어 역전 원리

의존성 역전 원리는 프레임워크의 가장 기본적인 설계 메커니즘이다.

의존성 역전은 의존성의 방향뿐만 아니라 제어 흐름의 주체 역시 역전시킨다.

전통적인 구조에서는 상위 정책의 코드가 하부의 구체적인 코드를 호출한다.

즉, 애플리케이션의 코드가 재사용 가능한 라이브러리나 툴킷의 코드를 호출한다.

 

그러나 의존성을 역전시킨 객체지향 구조에서는 반대로 프레임워크가 애플리케이션에 속하는 서브클래스의 메서드를 호출한다.

따라서 프레임워크를 사용할 경우 개별 애플리케이션에서 프레임워크로 제어 흐름의 주체가 이동한다.

즉, 의존성을 역전시키면 제어 흐름의 주체 역시 역전된다.

이를 제어 역전 원리, 또는 할리우드 원리라고 한다.

 

애플리케이션에 따라 달라질 수 있는 특정한 동작은 비워둔다.

그리고 이렇게 완성되지 않은 채로 남겨진 동작을 훅이라고 부른다.

재정의된 훅은 제어 역전 원리에 따라 프레임워크가 원하는 시점에 호출된다.

 

협력을 제어하는 것은 프레임워크다.

우리는 프레임워크가 적절한 시점에 실행할 것으로 예상되는 코드를 작성할 뿐이다.

객체지향의 시대에는 그저 프레임워크가 호출하는 코드를 작성해야만 한다.

제어가 우리에게서 프레임워크로 넘어가 버린 것이다.

 

우리의 코드는 수동적인 존재다.

프레임워크가 우리의 코드를 호출해줄 때까지 그저 넋 놓고 기다리고 있을 수밖에 없다.

 

만약 프레임워크를 처음 사용한다면 제어 흐름이 손가락 사이로 스멀스멀 빠져나가는 듯한 느낌에 불안해질 수도 있다.

그러나 이러한 제어의 역전이 프레임워크의 핵심 개념인 동시에 코드의 재사용을 가능하게 하는 힘이라는 사실을 이해해야 한다.