반응형
여러분, 알고리즘 인터뷰에서 동적 프로그래밍(DP) 문제를 접하면 많은 지원자가 “복잡하고 난해해”라며 당황하기 쉽습니다. DP는 문제를 작은 하위 문제(subproblem)로 나누고, 하위 문제의 해를 저장(memoization)하거나 테이블(tabulation)로 관리하여 중복 계산을 제거하는 기법입니다. 제대로 이해하고 패턴을 파악하면 DP 문제도 체계적으로 접근할 수 있으며, 면접 중에도 당황하지 않고 논리적으로 문제를 풀어나갈 수 있습니다.이번 글에서는 DP 문제를 만났을 때 어떤 접근 방법을 사용할지, 점화식(Recurrence Relation)을 어떻게 세우는지, 탑다운(Top-Down)과 바텀업(Bottom-Up) 접근 차이, 코너 케이스 처리, 복잡도 분석, 그리고 면접 상황에서 이 모든..
커맨드(Command) 패턴은 실행할 작업(명령)을 객체로 캡슐화하여, 명령을 매개변수로 전달하거나 큐잉, Undo/Redo, 비동기 실행 등의 기능을 가능하게 하는 중요한 패턴입니다. 하지만 전통적 구현(특히 C++98/03, 심지어 C++11/14/17 시절)에서는 다음과 같은 단점이 있었습니다.전통적 방식:추상 커맨드 인터페이스(abstract Command) 정의이를 상속하는 구체 커맨드 클래스 다수 정의 → 클래스 수 증가, 유지보수성 저하Undo/Redo, 비동기 처리, 로깅 추가 시 복잡성 폭발명령 교체, 에러 처리 등 구현이 번거로움하지만, C++20 이상 모던 C++에서는 람다, std::function, Concepts, std::expected, std::format, coroutin..
이전 글에서는 상태(State) 패턴을 모던 C++ 관점에서 재해석하며, 상속 기반 상태 클래스와 vtable에 의존하지 않고 std::variant, std::visit, Concepts, std::expected, std::format, Coroutines 등을 활용해 더 선언적이고 유지보수성 높은 상태 전이 로직을 구현할 수 있음을 확인했습니다. 이번에는 행동(Behavioral) 패턴 중 책임 연쇄(Chain of Responsibility) 패턴을 다룹니다.책임 연쇄 패턴은 요청(request)이 처리될 수 있는 핸들러(handler)들을 체인 형태로 연결하고, 각 핸들러가 요청을 처리하거나 다음 핸들러로 넘기는 구조를 제안합니다. 전통적으로는 상속 기반 핸들러 클래스 계층을 정의하고, setN..
이전 글에서는 옵저버(Observer) 패턴을 모던 C++ 관점에서 재해석하며, 상속 기반 인터페이스 대신 람다, std::function, std::expected, Ranges, 코루틴 등을 활용해 더욱 유연하고 타입 안전하며 이벤트 중심적인 구조를 구현할 수 있음을 확인했습니다. 이번에는 행동(Behavioral) 패턴 중 또 하나의 대표 주자인 상태(State) 패턴에 주목합니다.상태 패턴은 객체가 내부 상태에 따라 다른 행동을 하도록 하며, 상태 전이를 명확하게 표현하는 패턴입니다. 전통적으로는 상속 기반 상태 클래스와 가상 함수를 통해 상태 변화를 구현했지만, 모던 C++20 이상에서는 std::variant, std::visit, Concepts, 그리고 코루틴(coroutines) 등을 활..
지난 글에서는 전략(Strategy) 패턴을 모던 C++ 관점에서 재해석하며, 상속과 가상 함수를 통한 고전적 접근 대신 Concepts, 람다, std::function, std::expected, std::format 등 현대적 언어 기능을 활용해 상속 없이도 유연한 알고리즘 선택을 구현할 수 있음을 확인했습니다. 이번 글에서는 행동(Behavioral) 패턴 중 또 하나의 대표 주자인 옵저버(Observer) 패턴을 다룹니다.옵저버 패턴은 객체 간의 1:N 의존성을 정의해, 한 객체의 상태 변화 시 이를 의존하는 다른 객체(옵저버)에게 자동으로 통지하는 패턴입니다. 전통적으로는 "Subject가 Observer 리스트를 관리"하고 "상속 기반의 Update() 가상 함수 호출"을 통해 알림을 전달했..
지금까지 우리는 생성, 구조적 패턴들을 모던 C++ 관점에서 재해석하며 상속 계층, 가상 함수 테이블, 복잡한 클래스 증가 대신 Concepts, 람다, 함수 합성, std::expected, std::format, Ranges, std::variant 등을 활용해 더 간결하고 타입 안전하며 유지보수성 높은 코드를 작성할 수 있음을 확인했습니다. 이제는 행동(Behavioral) 패턴으로 넘어가 보겠습니다.행동 패턴은 객체 간의 상호작용, 책임 분배, 알고리즘 캡슐화를 다룹니다. 그 출발점으로 전략(Strategy) 패턴을 선택합니다. 전략 패턴은 알고리즘을 한 객체에 캡슐화하고, 이를 교체함으로써 런타임에 알고리즘을 선택할 수 있게 하는 패턴입니다. 전통적으로는 상속 기반 인터페이스를 통해 구현했지만,..
여러분, 코딩 인터뷰에서 정렬(Sorting)과 탐색(Searching)은 기본 중의 기본입니다. 단순하지만 중요한 개념이라 난이도를 자유롭게 조절할 수 있어 면접관이 선호하는 주제이며, 우선순위 큐(Priority Queue)나 이진 탐색(Binary Search)을 결합해 시간 복잡도를 최적화하는 문제도 자주 등장합니다. 이번 글에서는 정렬과 탐색, 우선순위 큐, 이진 탐색 패턴을 만나면 어떻게 접근하면 좋은지, 단계별로 아주 구체적이고 친절하게 풀어보겠습니다.우리는 단순히 “정렬 후 이진 탐색”이라는 키워드만 언급하고 끝나지 않고, 왜 이런 접근이 유효한지, 면접에서 이를 어떻게 표현할지, 코너 케이스나 추가 기능(비동기, 로깅, 에러 처리)을 어떻게 고려할지까지 모두 다루어보겠습니다. 이 글을 통..
지난 글에서는 플라이웨이트(Flyweight) 패턴을 모던 C++ 관점에서 재해석하며, 대량의 유사 객체 공유를 std::expected, std::string_view, Ranges, Concepts 등을 사용해 더 안전하고 유지보수성 높은 방식으로 구현할 수 있음을 살펴봤습니다. 이번 글에서는 구조적 패턴의 또 다른 핵심, 프록시(Proxy) 패턴을 다룹니다.프록시 패턴은 특정 객체(Real Subject)에 대한 접근을 제어하거나, 지연 로딩(Lazy Loading), 원격 호출(Remote Proxy), 캐싱(Caching) 등의 부가 기능을 중간에 삽입하는 기법을 제안합니다. 전통적 C++ 구현은 가상 함수를 통한 상속 기반 대리 객체로 접근했지만, 모던 C++20 이상의 기능을 활용하면 함수 ..
지난 글에서는 퍼사드(Facade) 패턴을 모던 C++ 관점에서 재해석하며, 모듈(Modules), Concepts, std::expected, std::format, std::variant 등을 활용해 복잡한 서브시스템을 단순화하는 전략을 살펴보았습니다. 이번 글에서는 또 하나의 구조적 패턴인 플라이웨이트(Flyweight) 패턴에 주목합니다.플라이웨이트 패턴은 다수의 유사한 객체를 효율적으로 다루기 위해, 공유 가능한 상태를 메모리 절약적으로 관리하는 방법을 제시합니다. 전통적으로는 "풀(Pool)을 두고 재활용"하거나 "공유된 객체를 전역 맵으로 관리"하는 방식으로 구현했으나, 모던 C++에서는 std::unordered_map, std::shared_ptr, std::string_view, Con..
지난 글에서는 데코레이터(Decorator) 패턴을 모던 C++ 관점에서 재해석하며, 상속 기반 장식(Decoration) 대신 함수 합성, 람다, Ranges 등을 활용해 기능 확장 과정을 유연하고 단순화할 수 있음을 확인했습니다. 이번 글에서는 퍼사드(Facade) 패턴에 주목합니다.퍼사드 패턴은 복잡한 서브시스템을 단일 인터페이스로 감싸, 클라이언트가 내부 구성 요소를 알 필요 없이 단순하고 일관된 방식으로 기능을 이용하도록 돕습니다. 전통적으로는 "정적인 클래스"나 "정적으로 링크된 라이브러리"를 단일 진입점으로 묶는 식으로 구현했지만, 모던 C++에서는 모듈(Modules), Concepts, std::expected, std::format 등을 활용해 퍼사드를 더 명확하고 문서화된 형태로 제공..