42의 박은종 멘토님과 함께 약 6주 간 진행한 스터디 그룹을 통해 공부한 자주 쓰이는 Design Pattern들을 정리해보았습니다. 생소했던 패턴을 케이스를 통해 익히면서 데이터를 어떻게 처리할 수 있을지 고민해볼 수 있었습니다.
디자인 패턴은 소프트웨어 디자인 과정에서 자주 발생하는 문제들에 대한 전형적인 해결책입니다. 이는 코드에서 반복되는 디자인 문제들을 해결하기 위해 맞춤화할 수 있는 미리 만들어진 청사진과 비슷합니다.
표준화된 라이브러리들이나 함수들을 코드에 복사해 사용하는 것처럼 패턴들을 붙여넣기식으로 사용할 수 없습니다. 패턴은 재사용할 수 있는 코드 조각이 아니라 특정 문제를 해결하는 방식을 알려주는 일반적인 개념입니다. 당신은 패턴의 세부 개념들을 적용하여 구현하고자 하는 프로그램에 맞는 해결책을 적용할 수 있습니다.
여기서 설명할 패턴은 알고리즘과 자주 혼동되기도 합니다. 왜냐하면 두 개념 모두 알려진 문제에 대한 일반적인 해결책을 설명하기 때문입니다. 알고리즘은 어떤 목표를 달성하기 위해 따라야 할 명확한 일련의 절차를 정의하지만, 패턴은 해결책에 대한 더 상위 수준의 설명입니다. 예를 들어 같은 패턴을 두 개의 다른 프로그램에 적용하면 두 프로그램의 코드는 다를 것입니다.
알고리즘은 요리법에 비유할 수 있지만 패턴은 요리법이 아닌 청사진에 더 가깝습니다. 알고리즘과 요리법 둘 다 목표를 달성하기 위한 명확한 단계들이 제시되어 있습니다. 반면에 청사진은 결과와 기능들은 제시하나 구현 단계 및 순서는 사용자가 결정합니다.
고로 패턴은 어떤 상황을 해결하기 위한 대략적인 해설지이기에, 구현하는 코드는 사람마다 차이가 있을 수 있습니다.
현실은 당신이 패턴에 대해 아무것도 알지 못해도 수년 동안 프로그래머로 일할 수 있다는 것입니다. 실제로 많은 프로그래머가 패턴에 대한 아무런 지식 없이 업무를 수행합니다. 또 자신도 모르는 사이에 일부 패턴들을 구현하고 있을 수도 있습니다. 그럼에도 왜 패턴을 배워야 하는지, 그 이유들을 정리해 보겠습니다.
디자인 패턴은 소프트웨어 디자인의 일반적인 문제들에 대해 시도되고 검증된 해결책들을 모은 것입니다. 이러한 문제들을 다루지 않더라도 패턴을 알고 있으면 여전히 쓸모가 있는데, 그 이유는 패턴을 배우게 되면 객체 지향 디자인의 원칙들을 사용해 많은 종류의 문제를 해결하는 방법들을 배울 수 있기 때문입니다.
디자인 패턴은 당신과 당신의 팀원들이 더 효율적으로 의사소통하는 데 사용할 수 있는 공통 언어를 정의합니다. 예를 들어서 당신의 팀이 디자인 패턴을 이해하면 업무 처리 중 당신이 '그 문제를 위해서는 그냥 싱글턴을 사용하세요'라고 말하면 모두가 당신이 무엇을 뜻했는지 이해할 수 있을 것이며 싱글턴 패턴에 포함된 개념들은 설명할 필요도 없을 것입니다.
고로, 객체 지향 디자인의 원칙들을 사용해 많은 종류를 효율적으로 해결할 수 있고, 팀원들과 더 효율적으로 의사소통하는 데 사용할 수 있기 때문에 배우는 것이 좋습니다.
디자인 패턴은 복잡성, 상세도 및 설계 중인 전체 시스템에 대한 적용 범위에 따라 분류됩니다. 저는 도로 건설에 비유하는 걸 좋아합니다. 교차로를 더 안전하게 만들기 위해 신호등을 설치하거나 보행자를 위한 지하도가 있는 전체 다층 인터체인지를 구축하는 작업에 비유할 수 있습니다.
가장 기본적인 하위 설계 패턴을 이디엄이라고 합니다. 일반적으로 이디엄은 단일 프로그래밍 언어에만 적용할 수 있습니다.
아키텍처 패턴은 상위 설계 패턴이며 가장 보편적으로 사용됩니다. 개발자들은 거의 모든 언어로 아키텍처 패턴들을 구현할 수 있으며 다른 패턴들과 달리 애플리케이션 전체의 구조(아키텍처)를 설계하는 데 사용할 수 있습니다.
또한 모든 패턴은 패턴의 의도 또는 목적에 따라 분류할 수 있습니다. 이 포스팅에서는 패턴의 주요 세 가지 그룹에 대해 다룹니다.
생성 패턴들은 기존 코드의 재활용과 유연성을 증가시키는 객체 생성 메커니즘들을 제공합니다.
구조 패턴은 구조를 유연하고 효율적으로 유지하면서 객체와 클래스를 더 큰 구조로 조합하는 방법을 설명합니다.
행동 패턴은 객체 간의 효과적인 의사소통과 책임 할당을 처리합니다.
생성 디자인 패턴은 기존 코드의 유연성과 재사용을 증가시키는 객체를 생성하는 다양한 방법을 제공합니다.
부모 클래스에서 객체를 생성할 수 있는 인터페이스를 제공하지만, 자식 클래스들이 생성될 객체의 유형을 변경할 수 있도록 합니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/factoryMethodPattern
관련 객체들의 구상 클래스들을 지정하지 않고도 그들의 패밀리들을 생성할 수 있습니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/abstractFactoryPattern
복잡한 객체들을 단계별로 생성할 수 있도록 합니다. 이 패턴은 같은 생성코드를 사용하여 객체의 다양한 유형들과 표현을 생성할 수 있습니다.
코드를 그들의 클래스들에 의존시키지 않고 기존 객체들을 복사할 수 있도록 합니다.
클래스에 인스턴스가 하나만 있도록 하면서 이 인스턴스에 대한 전역 접근(액세스) 지점을 제공합니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/singletonPattern
구조 패턴은 구조를 유연하고 효율적으로 유지하면서 객체들과 클래스들을 더 큰 구조로 조립하는 방법을 설명합니다.
호환되지 않는 인터페이스를 가진 객체들이 협업할 수 있도록 합니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/adapterPattern
큰 클래스 또는 밀접하게 관련된 클래스들의 집합을 두 개의 개별 계층구조(추상화 및 구현)로 나눈 후 각각 독립적으로 개발할 수 있도록 합니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/bridgePattern
객체들을 트리 구조들로 구성한 후, 이러한 트리 구조들이 개별 객체들인 것처럼 작업할 수 있도록 하는 디자인 패턴입니다
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/compositePattern
객체들을 새로운 행동들을 포함한 특수 래퍼 객체들 내에 넣어서 위 행동들을 해당 객체들에 연결시킵니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/decoratorPattern
라이브러리에 대한, 프레임워크에 대한 또는 다른 클래스들의 복잡한 집합에 대한 단순화된 인터페이스를 제공합니다.
각 객체에 모든 데이터를 유지하는 대신 여러 객체 간에 상태의 공통 부분들을 공유하여 사용할 수 있는 RAM에 더 많은 객체를 포함할 수 있도록 합니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/flyweight
다른 객체에 대한 대체 또는 자리표시자를 제공할 수 있습니다. 프록시는 원래 객체에 대한 접근을 제어하므로, 당신의 요청이 원래 객체에 전달되기 전 또는 후에 무언가를 수행할 수 있도록 합니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/proxyPattern
이러한 패턴들은 알고리즘들 및 객체 간의 책임 할당과 관련이 있습니다.
일련의 핸들러들의 사슬을 따라 요청을 전달할 수 있게 해주는 행동 디자인 패턴입니다. 각 핸들러는 요청을 받으면 요청을 처리할지 아니면 체인의 다음 핸들러로 전달할지를 결정합니다.
요청을 요청에 대한 모든 정보가 포함된 독립 실행형 객체로 변환합니다. 이 변환은 다양한 요청들이 있는 메서드들을 인수화할 수 있도록 하며, 요청의 실행을 지연 또는 대기열에 넣을 수 있도록 하고, 또 실행 취소할 수 있는 작업을 지원할 수 있도록 합니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/commandPattern
컬렉션의 요소들의 기본 표현(리스트, 스택, 트리 등)을 노출하지 않고 그들을 하나씩 순회할 수 있도록 합니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/iteratorPattern
객체 간의 혼란스러운 의존 관계들을 줄일 수 있습니다. 이 패턴은 객체 간의 직접 통신을 제한하고 중재자 객체를 통해서만 협력하도록 합니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/mediatorPattern
객체의 구현 세부 사항을 공개하지 않으면서 해당 객체의 이전 상태를 저장하고 복원할 수 있게 해줍니다.
여러 객체에 자신이 관찰 중인 객체에 발생하는 모든 이벤트에 대하여 알리는 구독 메커니즘을 정의할 수 있도록 합니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/observerPattern
객체의 내부 상태가 변경될 때 해당 객체가 그의 행동을 변경할 수 있도록 합니다. 객체가 행동을 변경할 때 객체가 클래스를 변경한 것처럼 보일 수 있습니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/statePattern
알고리즘들의 패밀리를 정의하고, 각 패밀리를 별도의 클래스들에 넣은 후 그들의 객체들을 상호교환할 수 있도록 합니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/strategyPattern
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/strategyPatternDB
부모 클래스에서 알고리즘의 골격을 정의하지만, 해당 알고리즘의 구조를 변경하지 않고 자식 클래스들이 알고리즘의 특정 단계들을 오버라이드(재정의)할 수 있도록 합니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/templateMethod
알고리즘들을 그들이 작동하는 객체들로부터 분리할 수 있습니다.
https://github.com/jungmyeong96/JavaDesignPatternStudy/tree/main/src/visitorPattren