/design-patterns

Head First Desgin Patterns Java code to CPP code

Primary LanguageC++

헤드퍼스트 디자인패턴을 공부하고 정리합니다. 책은 Java로 작성되었지만, C++로 코드를 작성했습니다.

객체 지향 기초

  • 추상화
  • 캡슐화
  • 다형성
  • 상속

객체지향 원칙

  • 바뀌는 부분은 캡슐화한다. 달라지는 부분을 찾아서 나머지 코드에 영향을 주지 않도록 캡슐화합니다. 코드를 변경하는 과정에서 의도치 않게 발생하는 일을 줄이면서, 스스템의 유연성을 향상시킬 수 있습니다.
  • 상속보다는 구성을 활용한다. 구성을 활용해서 시스텝을 만들면 유연성을 향상시킬 수 있습니다. 구성 요소로 사용하는 객체에서 올바른 행동 인터페이스를 구현한다면, 실행 시에 행동을 바꿀 수도 있습니다.
  • 구현보다는 인터페이스에 맞춰서 프로그래밍한다. "상위 형식에 맞춰서 프로그래밍한다"라는 다형성을 활용해야 한다는 의미입니다.
  • 상호작용하는 객체 사이에는 가능하면 느슨한 결합을 사용해야 한다. 객체들이 상호작용할 수는 있지만, 서로를 잘 모르는 관계를 의미합니다. 객체 사이의 상호의존성을 최소화 하여, 변경 사항이 생겨도 무난히 처리할 수 있는 유연한 객체지향 시스템을 구축할 수 있습니다.
  • OCP(Open-Closed Principle) 클래스는 확장에는 열려 있어야 하지만 변경에는 닫혀 있어야 합니다. 기존 코드를 건드리지 않고 확장으로 새로운 행동을 추가하는 것을 목표로 합니다.
  • 의존성 뒤집기 추상화된 것에 의존하게 만들고, 구상 클래스에 의존하지 않게 만듭니다.
  • 최소 지식 원칙(Principle of Least Knowledge), 진짜 절친에게만 이야기해야 합니다. 시스템을 디자인할 때 어떤 객체든 그 객체와 상호작용을 하는 클래스의 개수와 상호작용 방식에 주의를 기울여, 최소 결합을 해야 합니다.
  • 할리우드 원칙(Hollywood Principle), 먼저 연락하지 마세요. 저희가 연락 드리겠습니다. 의존성 부패(dependency rot)를 방지하기 위해, 슈퍼클래스에서 모든 것을 관리하고 필요한 서브클래스를 불러서 써야 합니다.
  • 어떤 클래스가 바뀌는 이유는 하나뿐이어야 한다. 클래스를 고치는 일은 최대한 피해야 합니다. 코드를 변경할 만한 이유가 많아지면 클래스를 코쳐야 할 가능성이 커지므로, 하나의 역할은 하나의 클래스에서만 맡아야 합니다.

객체지향 패턴

전략 패턴(Strategy Pattern)

알고리즘군을 정의하고 캡슐화해서 각각의 알고리즘을 수정해서 쓸 수 있게 해 줍니다. 클라이언트로부터 알고리즘을 분리해서 독립적으로 변경할 수 있습니다.

옵저버 패턴(Observer Pattern)

한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에게 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의존성을 정의합니다.

주제는 옵저버들이 Observer인터페이스를 구현한다는 것을 제외하면 옵저버에 관해 전혀 모릅니다. 따라서 이들 사이의 결합은 느슨한 결합입니다.

데코레이터 패턴(Decorator Pattern)

객체에 추가 요소를 동적으로 더할 수 있습니다. 데코레이터를 사용하면 서브클래스를 만들 때보다 훨씬 유연하게 기능을 확장할 수 있습니다.

자신이 장식하고 있는 객체에게 어떤 행동을 위임하는 일 말고도 추가 작업을 수행할 수 있습니다. 데코레이터 패턴을 사용하면 자잘한 객체가 매우 많이 추가될 수 있고, 데코레이터를 너무 많이 사용하면 코드가 필요 이상으로 복잡해집니다.

팩토리 패턴(Factory Pattern)

객체 생성을 캡슐화합니다.

팩토리 메소드 패턴

객체를 생성할 때 필요한 인터페이스를 만들고, 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정합니다. 인스턴스 만드는 일을 서브클래스에 맡길 수 있습니다.

추상 팩토리 패턴

구상 클래스에 의존하지 않고도 서로 연관되거나 의존적인 객체로 이루어진 제품군을 생산하는 인터페이스를 제공합니다. 구상 클래스는 서브클래스에서 만듭니다.

싱글턴 패턴(Singleton Pattern)

클래스 인스턴스를 하나만 만들고, 그 인스턴스로의 전역 접근을 제공합니다.

간단해 보이지만, 구현할 때 멀티 스레드와 같은 여러가지 자질구레한 부분에 신경을 써야 합니다.

커맨드 패턴(Command Pattern)

요청 내역을 객체로 캡슐화해서 객체를 서로 다른 요청 내역에 따라 매개변수화할 수 있습니다.

요청을 큐에 저장하거나 로그로 기록하거나 작업 취소 기능을 사용할 수 있습니다.

어댑터 패턴(Adapter Pattern)

특정 클래스 인터페이스를 클라이언트에서 요구하는 다른 인터페이스로 변환합니다. 인터페이스가 호환되지 않아 같이 쓸 수 없었던 클래스를 사용할 수 있게 도와줍니다.

퍼사드 패턴(Facade Pattern)

서브시스템에 있는 일련의 인터페이스를 통합 인터페이스로 묶어 줍니다. 또한 고수준 인터페이스도 정의하므로 서브시스템을 더 편리하게 사용할 수 있습니다.

템플릿 메소드 패턴(Template Method Pattern)

알고리즘의 골격을 정의합니다. 템플릿 메소드를 사용하면 알고리즘의 일부 단계를 서브클래스에서 구현할 수 있으며, 알고리즘의 구조는 그대로 유지하면서 알고리즘의 특정 단계를 서브클래스에서 재정의할 수도 있습니다.

반복자 패턴(Iterator Pattern)

컬렉션의 구현 방법을 노출하지 않으면서 집합체 내의 모든 항목에 접근하는 방법을 제공합니다.

각 항목에 일일이 접근할 수 있게 해 주는 기능을 집합체가 아닌 반복자 객체가 책임진다는 장점이 있어, 집합체 인터페이스와 구현이 간단해지고 각자에게 중요한 일만을 처리할 수 있게 됩니다.

컴포지트 패턴(Composite Pattern)

객체를 트리구조로 구성해서 부분-전체 계층 구조를 구현합니다. 클라이언트에서 개별 객체와 복합 개체를 똑같은 방법으로 다룰 수 있습니다.

상태 패턴(State Pattern)

내부 상태가 바뀜에 따라 객체의 행동이 바뀔 수 있도록 해 줍니다. 마치 객체의 클래스가 바뀌는 것 같은 결과를 얻을 수 있습니다.

전략 패턴과 구조가 비슷하지만, 상태를 바꾸는 걸 염두에 둔 디자인으로 목적이 다릅니다.

프록시 패턴(Proxy Pattern)

특정 개체로의 접근을 제어하는 대리인(특정 객체를 대변하는 객체)을 제공합니다.

복합 패턴(Combined Pattern)

2개 이상의 패턴을 결합해서 일반적으로 자주 등장하는 문제들의 해법을 제공합니다.

대표적인 예로 MVC가 있습니다.