헤드퍼스트 디자인패턴
을 공부하고 정리합니다.
책은 Java
로 작성되었지만, C++
로 코드를 작성했습니다.
- 추상화
- 캡슐화
- 다형성
- 상속
- 바뀌는 부분은 캡슐화한다.
달라지는 부분을 찾아서 나머지 코드에 영향을 주지 않도록
캡슐화
합니다. 코드를 변경하는 과정에서 의도치 않게 발생하는 일을 줄이면서, 스스템의 유연성을 향상시킬 수 있습니다. - 상속보다는 구성을 활용한다. 구성을 활용해서 시스텝을 만들면 유연성을 향상시킬 수 있습니다. 구성 요소로 사용하는 객체에서 올바른 행동 인터페이스를 구현한다면, 실행 시에 행동을 바꿀 수도 있습니다.
- 구현보다는 인터페이스에 맞춰서 프로그래밍한다.
"상위 형식에 맞춰서 프로그래밍한다"라는
다형성
을 활용해야 한다는 의미입니다. - 상호작용하는 객체 사이에는 가능하면 느슨한 결합을 사용해야 한다. 객체들이 상호작용할 수는 있지만, 서로를 잘 모르는 관계를 의미합니다. 객체 사이의 상호의존성을 최소화 하여, 변경 사항이 생겨도 무난히 처리할 수 있는 유연한 객체지향 시스템을 구축할 수 있습니다.
- OCP(Open-Closed Principle) 클래스는 확장에는 열려 있어야 하지만 변경에는 닫혀 있어야 합니다. 기존 코드를 건드리지 않고 확장으로 새로운 행동을 추가하는 것을 목표로 합니다.
- 의존성 뒤집기 추상화된 것에 의존하게 만들고, 구상 클래스에 의존하지 않게 만듭니다.
- 최소 지식 원칙(Principle of Least Knowledge), 진짜 절친에게만 이야기해야 합니다. 시스템을 디자인할 때 어떤 객체든 그 객체와 상호작용을 하는 클래스의 개수와 상호작용 방식에 주의를 기울여, 최소 결합을 해야 합니다.
- 할리우드 원칙(Hollywood Principle), 먼저 연락하지 마세요. 저희가 연락 드리겠습니다. 의존성 부패(dependency rot)를 방지하기 위해, 슈퍼클래스에서 모든 것을 관리하고 필요한 서브클래스를 불러서 써야 합니다.
- 어떤 클래스가 바뀌는 이유는 하나뿐이어야 한다. 클래스를 고치는 일은 최대한 피해야 합니다. 코드를 변경할 만한 이유가 많아지면 클래스를 코쳐야 할 가능성이 커지므로, 하나의 역할은 하나의 클래스에서만 맡아야 합니다.
알고리즘군을 정의하고 캡슐화해서 각각의 알고리즘을 수정해서 쓸 수 있게 해 줍니다. 클라이언트로부터 알고리즘을 분리해서 독립적으로 변경할 수 있습니다.
한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에게 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의존성을 정의합니다.
주제는 옵저버들이 Observer
인터페이스를 구현한다는 것을 제외하면 옵저버에 관해 전혀 모릅니다. 따라서 이들 사이의 결합은 느슨한 결합입니다.
객체에 추가 요소를 동적으로 더할 수 있습니다. 데코레이터를 사용하면 서브클래스를 만들 때보다 훨씬 유연하게 기능을 확장할 수 있습니다.
자신이 장식하고 있는 객체에게 어떤 행동을 위임하는 일 말고도 추가 작업을 수행할 수 있습니다. 데코레이터 패턴을 사용하면 자잘한 객체가 매우 많이 추가될 수 있고, 데코레이터를 너무 많이 사용하면 코드가 필요 이상으로 복잡해집니다.
객체 생성을 캡슐화합니다.
객체를 생성할 때 필요한 인터페이스를 만들고, 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정합니다. 인스턴스 만드는 일을 서브클래스에 맡길 수 있습니다.
구상 클래스에 의존하지 않고도 서로 연관되거나 의존적인 객체로 이루어진 제품군을 생산하는 인터페이스를 제공합니다. 구상 클래스는 서브클래스에서 만듭니다.
클래스 인스턴스를 하나만 만들고, 그 인스턴스로의 전역 접근을 제공합니다.
간단해 보이지만, 구현할 때 멀티 스레드와 같은 여러가지 자질구레한 부분에 신경을 써야 합니다.
요청 내역을 객체로 캡슐화해서 객체를 서로 다른 요청 내역에 따라 매개변수화할 수 있습니다.
요청을 큐에 저장하거나 로그로 기록하거나 작업 취소 기능을 사용할 수 있습니다.
특정 클래스 인터페이스를 클라이언트에서 요구하는 다른 인터페이스로 변환합니다. 인터페이스가 호환되지 않아 같이 쓸 수 없었던 클래스를 사용할 수 있게 도와줍니다.
서브시스템에 있는 일련의 인터페이스를 통합 인터페이스로 묶어 줍니다. 또한 고수준 인터페이스도 정의하므로 서브시스템을 더 편리하게 사용할 수 있습니다.
알고리즘의 골격을 정의합니다. 템플릿 메소드를 사용하면 알고리즘의 일부 단계를 서브클래스에서 구현할 수 있으며, 알고리즘의 구조는 그대로 유지하면서 알고리즘의 특정 단계를 서브클래스에서 재정의할 수도 있습니다.
컬렉션의 구현 방법을 노출하지 않으면서 집합체 내의 모든 항목에 접근하는 방법을 제공합니다.
각 항목에 일일이 접근할 수 있게 해 주는 기능을 집합체가 아닌 반복자 객체가 책임진다는 장점이 있어, 집합체 인터페이스와 구현이 간단해지고 각자에게 중요한 일만을 처리할 수 있게 됩니다.
객체를 트리구조로 구성해서 부분-전체 계층 구조를 구현합니다. 클라이언트에서 개별 객체와 복합 개체를 똑같은 방법으로 다룰 수 있습니다.
내부 상태가 바뀜에 따라 객체의 행동이 바뀔 수 있도록 해 줍니다. 마치 객체의 클래스가 바뀌는 것 같은 결과를 얻을 수 있습니다.
전략 패턴과 구조가 비슷하지만, 상태를 바꾸는 걸 염두에 둔 디자인으로 목적이 다릅니다.
특정 개체로의 접근을 제어하는 대리인(특정 객체를 대변하는 객체)을 제공합니다.
2개 이상의 패턴을 결합해서 일반적으로 자주 등장하는 문제들의 해법을 제공합니다.
대표적인 예로 MVC가 있습니다.