개발 시 반복적으로 등장하는 문제를 해결하기 위한 일반화된 솔루션
패턴 이름 (name)
각 패턴은 특정한 문제 해결 방법을 설명하는 고유한 이름을 가짐
문제 (problem)
패턴이 해결하려는 특정 상황 또는 문제를 설명
해결책 (solution)
문제를 해결하기 위한 설계나 전략을 제시
이는 구체적인 코드가 아닌 추상적인 설명으로, 다양한 상황에 적용될 수 있음
결과 (result)
패턴 사용의 결과, 이점 및 잠재적인 단점 포함
코드 재사용성 향상
- 잘 정의된 패턴을 사용함으로써 반복적인 작업을 줄이고, 이미 검증된 솔루션을 활용하여 효율성을 높일 수 있음
- 개발 시간을 단축 시키고, 전반적인 프로젝트 비용을 줄이는 데 기여
유지보수 용이성
- 명확하고 일관된 설계 접근 방식을 채택함으로써, 코드는 더 읽기 쉽고 이해하기 쉬워짐
- 버그의 식별과 수정을 용이하게 하고, 시스템의 확장성과 유연성을 향상시킴
팀 커뮤니케이션 개선
- 공통된 용어와 개념을 사용함으로써, 팀원들은 더 빠르고 정확하게 아이디어를 전달하고 이해할 수 있음
- 협업을 강화하고, 프로젝트의 진행 속도를 높이는 데 중요한 역할을 함
효과적인 문제 해결
- 각 패턴은 특정 문제 유형에 최적화된 해결책을 제공하며, 이를 통해 개발자들은 신속하게 문제에 접근할 수 있음
장기적인 시스템 안정성
- 검증된 패턴의 사용은 시스템의 장기적인 안정성과 신뢰성을 보장
- 소프트웨어가 시간이 지남에 따라 변경되고 확장될 때 중요한 이점을 제공
단일 책임 원칙 (Single Responsibility Principle)
- 각 클래스는 하나의 기능 또는 책임만을 가져야 함
- 코드의 복잡성을 줄이고, 유지보스를 용이하게 함
개방-폐쇄 원칙 (Open-Closed Principle)
- 소프트웨어 엔티티는 확장에는 열려 있어야 하지만, 수정에는 닫혀 있어야 함
- 기존 코드를 변경하지 않고도 시스템의 기능을 확장할 수 있도록 함
리스코프 치환 원칙 (Liskov Substitution Principle)
- 파생 클래스는 기반 클래스의 기능을 손상시키지 않으면서 대체 가능해야 함
인터페이스 분리 원칙 (Interface Segregation Principle)
- 클라이언트는 사용하지 않는 메소드에 의존하도록 강제되어서는 안됨
- 더 작고 구체적인 인터페이스로 분리하는 것이 바람직함
의존성 역전 원칙 (Dependency Inversion Principle)
- 고수준 모듈은 저수준 모듈에 의존해서는 안되며, 둘 다 추상화에 의존해야 함
객체를 생성할 때와 관련된 문제에 대한 해결책을 다룸
객체 생성과정을 보다 유연하게 만들어주며, 코드의 타이트한 결합을 방지함
ex. 공장에서 물건을 찍어내는 것 (물건-객체)
싱글턴 (Singleton)
한 클래스의 인스턴스가 오직 하나만 존재하도록 보장
팩토리 메소드 (Factory Method)
객체 생성을 서브 클래스에 위임하며, 클라이언트 코드가 특정 클래스의 인스턴스화와 분리됨
추상 팩토리 (Abstract Factory)
관련된 객체의 패밀리를 생성하기 위한 인터페이스를 제공함
빌더 (Builder)
복잡한 객체의 구축과 표현을 분리하며, 동일한 구축 과정으로 다양한 표현을 생성할 수 있음
프로토타입 (Prototype)
기존 객체를 복제하여 새로운 객체를 생성
클래스와 객체를 조합하여 더 큰 구조를 형성하는 방법에 관한 것
여러개의 객체들의 구조를 어떻게 구성할지가 이 패턴의 주 관심사
어댑터 (Adapter)
호환되지 않는 인터페이스를 가진 클래스들이 함께 작동할 수 있도록 함
브릿지 (Bridge)
추상화와 구현을 분리하여, 독립적으로 변형될 수 있음
컴포지트 (Composite)
객체들을 트리 구조로 구성하여, 개별 객체와 복합 객체를 동일하게 취급할 수 있음
데코레이터 (Decorator)
객체에 동적으로 새로운 책임을 추가함
퍼사드 (Facade)
복잡한 시스템에 대한 간단한 인터페이스를 제공함
플라이웨이트 (Flyweight)
공유를 통해 작은 객체들의 수를 줄임
프록시 (Proxy)
다른 객체에 대한 접근을 제어하는 대리자 또는 자리표시자 역할을 함
객체들 사이의 통신과 책임의 분배에 초점을 맞춤
복잡한 흐름 제어를 간소화하고, 객체 간의 상호 작용을 더 효과적으로 만듦
ex. 특정 객체가 변할 때 다른 객체들에 이 상태를 어떻게 전달할지
책임 연쇄 (Chain of Responsibility)
요청을 처리할 수 있는 객체의 체인을 통해 요청을 전달함
커맨드 (Command)
요청을 객체로 캡슐화하여, 사용자 정의 요청에 따라 매개변수화할 수 있음
인터프리터 (Interpreter)
주어진 언어의 문법에 대한 표현을 정의하고, 해당 언어로 작성된 문장을 해석함
이터레이터 (Iterator)
컬렉션 내의 요소를 순차적으로 접근하는 방법을 제공
중재자 (Mediator)
객체들 간의 복잡한 통신을 조정하고 제어함
메멘토 (Memento)
객체의 상태를 이전 상태로 복원할 수 있는 방법을 제공
옵저버 (Observer)
객체의 상태 변화를 관찰하고, 이에 따라 다른 객체들이 반응할 수 있도록 함
상태 (State)
객체의 내부 상태에 따라 객체의 행동을 변경함
전략 (Strategy)
알고리즘을 객체의 행동으로 캡슐화하여, 동일한 행동을 다른 알고리즘으로 교체할 수 있음
템플릿 메소드 (Template Method)
알고리즘의 골격을 정의하고, 일부 단계를 서브클래스에서 구현하도록 함
방문자 (Visitor)
객체 구조의 요소에 대한 연산을 정의하여, 구조의 요소가 연산을 수행하도록 함
선택한 패턴이 시스템의 유연성과 확장성을 향상시키는지 평가
일부 패턴은 추가적인 추상화 레벨을 도입함으로써 시스템의 성능에 영향을 줄 수 있음
성능 요구사항을 고려하여 패턴을 적용해야 함
패턴은 문제 해결의 명확성을 제공하지만, 때로는 시스템의 복잡성을 증가시킬 수도 있음
필요 이상의 패턴 사용을 피하고, 가독성과 유지보수를 고려해야 함
오버 엔지니어링 (Overengineering)
- 디자인 패턴을 필요 이상으로 사용하면, 시스템이 불필요하게 복잡해질 수 있음
- 이는 코드의 가독성과 유지보수성을 저하시킬 수 있음
적합하지 않은 상황에서의 사용
- 모든 설계 문제에 디자인 패턴을 적용하려는 시도는 때때로 문제를 더 복잡하게 만들 수 있음
- 패턴은 특정 문제에 대한 해결책이며, 모든 상황에 적합한 것은 아님
추가적인 추상화 수준
- 일부 디자인 패턴, 특히 구조적 패턴은 추가적인 추상화 레이어를 도입함
- 이는 유연성을 향상시키지만, 동시에 시스템의 성능에 부정적인 영향을 줄 수 있음
성능 저하
- 특정 패턴, 예를 들어 싱글턴이나 플라이웨이트는 성능을 최적화하는 데 도움이 될 수 있지만, 잘못 사용될 경우 오히려 성능 저하를 초래할 수 있음
상황에 따른 적용
- 디자인 패턴은 모든 설계 문제에 대한 해결책이 될 수 없음
- 각 패턴의 적용은 해당 문제의 맥락과 요구사항을 고려하여 신중하게 이루어져야 함
지속적인 학습과 적응
- 소프트웨어 개발 분야는 지속적으로 변화하고 있으며, 디자인 패턴 또한 새로운 기술과 방법론에 맞추어 진화해야 함
- 개발자는 지속적으로 학습하고, 새로운 패턴을 탐색하며, 기존의 패턴을 재평가할 필요가 있음