GoF (Gang of Four) 디자인 패턴
패턴 (Pattern)
- 특정한 문제를 해결하는 과정이나 방법 등이 유사한 걸 발견할 수 있다.
- 패턴은 문제를 해결하는 과정을 일반화한 것.
- 한 패턴이 다른 패턴에 중복적으로 사용되는 경우도 있다.
- 디자인 패턴을 구별하는 기준
- 각각의 패턴이 어떤 관심사나 관점에서 문제를 해결하려는 가로 구분한다.
- 즉, 패턴은 의도와 목적에 따라 달라진다.
소프트웨어 공학
패턴의 원리는 소프트웨어 공학에도 도입되었고,
소프트웨어적 문제를 코드로 구현할 때 적용한 방법을 “패턴화”했다.
객체지향 (OOP : Object Oriented Programming)
- 스몰토크, C++, 자바, PHP 등등의 언어가 지원한다.
- 객체지향 기반 개발 시 어려운 점 : 각각의 코드를 “재사용” 가능한 형태의 코드로 작성하는 것.
패턴 발견
- 객체지향 개발론은 큰 프로젝트의 개발과 유지 보수를 보다 쉽게 하기 위해 도입된 개발 방법론이다.
- 최근 프로그램들이 대형화, 분업화하며 절차지향에서 객체지향으로 이동하고 있다.
(그러면서 디자인 패턴 또한 함께 주목받았다.)
- 많은 개발자들이 소프트웨어 개발에서
특정 문제를 유사한 유형으로 해결한다는 것을 알게 됐다.
- 해결 과정에서 발견된 방법들을 패턴화하여 규정했다.
- 패턴은 객체지향 문제를 해결하기 위해 도입되었다.
해결책
- 객체지향에서 디자인 패턴이 해결하는 주요 문제
- 디자인 패턴 : 객체지향 문제를 해결하기 위한 일련의 코드 스타일
- 디자인 패턴을 적용하기 위해선 객체지향적 코드를 작성할 수 있는 언어가 필요하다.
설계 원칙
- 객체지향 코딩 시, 가급적 지켜야 할 원칙이 있다.
- SOLID 원칙
- Single Responsibility Principle : SRP : 단일 책임의 원칙
- 작성된 클래스는 하나의 기능만 가지며,
클래스가 제공하는 모든 서비스는 그 하나의 책임을 수행하는데 집중되어야 한다.
- 어떤 변화에 의해 클래스를 변경해야하는 이유는 오직 하나 뿐이어야 한다.
- Open / Closed Principle : OCP : 개방-폐쇄 원칙
- 소프트웨어의 구성 요소(컴포넌트, 클래스, 모듈, 함수)는
확장에는 열려있고 변경에는 닫혀있어야 한다.
- 변경을 위한 비용은 가능한 줄이고, 확장을 위한 비용을 가능한 극대화한다.
- 요구사항의 변경 및 추가사항이 발생하더라도, 기존 구성 요소는 수정이 일어나지 않아야하며, 기존 구성 요소를 쉽게 확장해서 재사용할 수 있어야한다.
- Liskov Substitution Principle : LSP : 리스코프 치환 원칙
- 서브 타입은 언제나 기반 타입과 호환될 수 있어야 한다.
- ⇒ 서브 타입은 기반 타입이 약속한 규약을 지켜야 한다.
- 상속은 구현 상속, 인터페이스 상속이든
궁극적으로 다형성을 통한 확장성 획득을 목표로한다.
- Interface Segregation Principle : ISP : 인터페이스 분리의 원칙
- 한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다는 원리이다.
- 어떤 클래스가 다른 클래스에 종속될 때, 가능한 최소한의 인터페이스만 사용해야 한다.
- 하나의 일반적인 인터페이스 보다는 여러 개의 구체적인 인터페이스가 낫다.
- Dependency Inversion Principle : DIP : 의존 관계 역전의 원칙
- “추상화에 의존해야지, 구체화에 의존하면 안된다.”
- 의존 관계 역전 : 구조적 디자인에서 발생하던 하위 모듈의 변경이 상위 모듈의 변경을 요구하는 위치 관계를 끊는 의미의 역전.
- 실제 사용 관계는 바뀌지 않으며, 추상을 매개로 메시지를 주고 받음으로써 관계를 최대한 느슨하게 만드는 원칙.
- 위 원칙들은 객체지향 코드를 작성하는데 도움을 주지만,
시스템을 고려하지 않은 원칙을 적용할 경우 불필요한 일이 발생할 수도 있다.
즉, 각각의 원칙들은 코드의 목적에 맞게 적재적소에 적용되어야 한다.
GoF : Gang of Four
에릭 감마, 리처드 헬름, 랄프 존슨, 존 블라지데스의 저서 “GoF 디자인 패턴”을 가리키는 용어
(처음 소프트웨어 공학에서 사용되는 패턴을 정리한 사람들의 별칭)
패턴 카탈로그
- 디자인 패턴은 갑자기 생겨난 방식이 아닌,
이미 일상적으로 개발 작업 속에서 자연스럽게 사용된다.
- GoF : 객체지향 분야의 문제점을 분석해 24개 패턴으로 분류했다.
⇒ 기존에 객체지향 문제를 카탈로그화 해서 패턴으로 정리했다.
통일성
- 협업으로 대규모 프로젝트를 진행할 때, 가장 중요한 요소이다.
- 통일된 개발 방식의 공유
- 서로 개발하는 방식에 차이가 있을 경우, 최종 결과물로 통합하는 과정이 어려워진다.
- 디자인 패턴 : 개발 방법을 정의하여 보다 통일화된 좋은 코드를 작성할 수 있다.
- 개발자가 자신의 코드를 다른 사람과 소통하는데 좋은 가이드가 될 수 있다.
실체화 (Reification)
- = 실제로 만든다.
- != 구현 (Implementation)
- 실체화는 코드가 아니라 디자인(설계)를 의미한다.
- 구조만으로 패턴을 파악하는 것은 불가능.
- 패턴을 파악하려면 의도를 알아야 한다.
- 이에 어떤 문제를 해결하기 위해 2개 이상의 패턴을 혼합하는 경우가 많다.
패턴의 요소
24개로 분리된 패턴은 공통된 4가지 요소를 가지고 있다.
-
이름
Pattern name
-
문제
Problem
-
해법
Solution
-
결과
Consequence
이름 (Pattern Name)
- 24개의 디자인 패턴은 각각의 고유한 이름이 있다.
- 패턴의 이름을 통해 용도를 직관적으로 이해할 수 있다.
- 코드 패턴의 스타일이나 해결하려는 용도에 따라 패턴의 이름을 결정한다.
문제 (Problem)
- 각 패턴은 해결하고자 하는 문제가 있다.
- 문제들은 패턴 적용을 고려해야 하는 시점을 암시한다.
- 코드에서 해결할 문제점을 발견한 후
⇒ 그와 관련된 여러 배경을 먼저 정리한다.
⇒ 이런 문제점을 해결할 수 있는 다양한 적용 사례를 모색한다.
해법 (Solution)
- 문제점을 인식했다면 해결 방법을 찾아야 한다.
- 이를 위해 객체 요소 간 관계를 정리하고
- 패턴은 객체들을 추상화하는 과정을 거친다.
- 또한, 해결을 위한 객체를 나열한다.
결과 (Consequence)
- 디자인 패턴은 알려진 문제점을 해결하는데 효과적이다.
- 하지만, 디자인 패턴을 적용한다 해서 모든 문제를 완벽하게 제거할 순 없다.
- 24개의 디자인 패턴은 다양한 문제를 해결할 수 있는 선배 개발자의 경험에서 나온 것이다.
- 모든 코드에서 디자인 패턴이 유용하다고 볼 순 없다.
- 패턴은 유용하지만 꼭 필요한 경우를 생각해서 적절히 분배하여 사용한다.
유지 보수
디자인 패턴은 소프트웨어의 유지 보수성을 개선한다.
소프트웨어의 수명
- 소프트웨어는 하드웨어와 달리 시간의 경과에 따라 닳거나 소모되지 않는다.
- 한번 작성된 코드는 시스템 환경이 변하지 않는 한, 지속적으로 동작한다.
- 하지만, 소프트웨어는 기능이 추가되고 수정이 많이 발생한다.
- 디자인 패턴을 적용하는 목적 중 하나 : 유지 보수성
- 유지 보수성 : 향후 추가되는 코드를 수정하기 위해 쉽게 변경할 수 있도록 쓰인 코드를 의미.
- 소프트웨어 유지 보수 기간 : 통상적으로 10년
방어적 설계
- 오랫동안 문제 없이 유지 보수하기 위해선
변경 가능한 디자인(Design For Change)으로 설계되어야 한다.
- 코딩 중 어떤 부분이 향후 수정될 것이라 예측되면
해당 부분을 방어적으로 처리할 수 있도록 설계한다.
- 방어적 설계를 위해 지속적으로 코드를 개선하는 리팩터링 작업을 실시한다.
정리
- 코딩 시, 유지 보수성과 성능적인 부분을 고려해야 한다.
- 한 코드를 파악하려면 학습 시간이 필요하다.
⇒ 디자인 패턴에 숙련되면 이런 시간을 단축할 수 있다.
- 장점 : 디자인 패턴은 문제해결 방법 외에도 시간 절약에도 유용하다.
- 성능 최적화를 위해선 많은 함수의 호출과 객체 간의 호출이 적을수록 좋다.
⇒ 디자인 패턴에선 코드의 가독성과 유지 보수를 위해
객체의 매서드를 분리하고 호출도 자주 발생한다.
- 단점 : 디자인 패턴을 너무 많이 사용하면 잦은 메서드 호출로 성능이 저하될 수 있다.
- 디자인 패턴 적용 시, 장단점을 고려해야 한다.