반응형
이전 글에서는 미디에이터(Mediator) 패턴을 모던 C++ 관점에서 재해석하며, 상속 기반 구조 없이도 Concepts, std::function, std::expected, coroutine, Ranges 등을 활용해 객체 간 상호작용을 유연하고 타입 안전하게 구현할 수 있음을 확인했습니다. 이번에는 행동(Behavioral) 패턴 중 메멘토(Memento) 패턴을 다룹니다.메멘토 패턴은 객체 상태를 캡슐화(스냅샷)하여, 이후 필요할 때 원래 상태로 복원하는 기법을 제공합니다. 전통적으로는 Originator(원본 객체), Memento(상태 저장), Caretaker(메멘토 관리) 클래스를 정의하고, Memento 클래스로 상태를 저장/복원하는 상속 기반 구조를 사용했습니다. 그러나 모던 C++2..
이전 글에서는 인터프리터(Interpreter) 패턴을 모던 C++ 관점에서 재해석하며, 상속 기반 Expression 클래스 계층 없이도 std::variant, std::visit, Concepts, std::expected, Ranges, coroutine 등을 활용해 언어 해석 로직을 단순하고 확장성 높게 구현할 수 있음을 확인했습니다. 이번 글에서는 행동(Behavioral) 패턴 중 이터레이터(Iterator) 패턴을 다룹니다.이터레이터 패턴은 컬렉션의 내부 표현을 노출하지 않고, 요소에 접근하는 통일된 인터페이스를 제공하는 패턴입니다. 전통적으로는 컬렉션 별로 Iterator 인터페이스를 정의하고, begin()/end() 또는 next(), hasNext() 등의 메서드를 통해 요소 순회가..
지난 글에서는 퍼사드(Facade) 패턴을 모던 C++ 관점에서 재해석하며, 모듈(Modules), Concepts, std::expected, std::format, std::variant 등을 활용해 복잡한 서브시스템을 단순화하는 전략을 살펴보았습니다. 이번 글에서는 또 하나의 구조적 패턴인 플라이웨이트(Flyweight) 패턴에 주목합니다.플라이웨이트 패턴은 다수의 유사한 객체를 효율적으로 다루기 위해, 공유 가능한 상태를 메모리 절약적으로 관리하는 방법을 제시합니다. 전통적으로는 "풀(Pool)을 두고 재활용"하거나 "공유된 객체를 전역 맵으로 관리"하는 방식으로 구현했으나, 모던 C++에서는 std::unordered_map, std::shared_ptr, std::string_view, Con..
앞선 글에서는 브리지(Bridge) 패턴을 통해 모던 C++에서 상속 기반의 전통적 설계를 어떻게 Concepts, 함수 객체, std::variant 등으로 대체하며 더 유연한 구조를 만들 수 있는지 살펴보았습니다. 이번에는 데코레이터(Decorator) 패턴을 재조명합니다.데코레이터 패턴은 객체에 기능을 동적으로 추가하는 방법을 제시합니다. 전통적으로는 상속이나 래핑(wrapper) 클래스를 사용해 "장식(Decoration)"을 더했지만, 모던 C++에서는 람다, std::function, Ranges, Concepts 등의 기능을 활용해 상속 계층 폭발을 줄이고, 훨씬 간결하고 가독성 높은 코드로 기능을 확장할 수 있습니다.패턴 소개: 데코레이터(Decorator)의도:객체에 추가 책임(기능)을 ..
이전 글에서는 추상 팩토리(Abstract Factory) 패턴을 모던 C++로 재해석하며, 상속 기반의 전통적 구현 방식이 어떻게 Concepts, std::expected, std::variant 등을 활용해 보다 탄탄하고 유연한 구조로 바뀔 수 있는지 알아보았습니다. 이번에는 브리지(Bridge) 패턴에 주목합니다.브리지 패턴의 핵심 의도는 "추상(Abstraction)과 구현(Implementation)을 분리하여 둘을 독립적으로 확장할 수 있게 하는 것"입니다. 전통적인 C++ 구현에서는 추상 클래스 계층과 구현 클래스 계층을 상속으로 연결하는 경향이 많았으나, 모던 C++에서는 Concepts, 컴포지션(합성), std::function, 그리고 Ranges나 람다를 통한 파이프라인형 사고로 ..
C++20 이상의 모던 C++ 언어 기능들은 개발자들에게 이전에는 상상하기 어려웠던 수준의 표현력, 안전성, 유지보수성을 제공합니다. 한편, 소프트웨어 개발의 전통적인 지식인 “디자인 패턴(Design Patterns)”은 여전히 유지보수성과 확장성이 요구되는 대규모 코드베이스에서 널리 활용되는 개념입니다.이 시리즈에서는 고전적인 GoF(Gang of Four) 디자인 패턴들을 모던 C++ 스타일로 재구현하며, 기존 C++11/14/17 시대의 구현 방식과 비교 분석할 것입니다. 이를 통해 독자들은 각 패턴의 본질을 재확인하는 동시에, Concepts, Ranges, Coroutines, std::format, std::expected, std::jthread, std::variant, std::stri..
과거 C++98/03 시절에는 표준 라이브러리가 제공하는 알고리즘도 제한적이었고, 특정 요구사항을 만족하기 위해 개발자가 직접 알고리즘을 구현하거나, 반복자 기반 STL 알고리즘을 복잡하게 조합해야 하는 경우가 많았습니다. 또한 병렬 처리나 고성능 연산을 위해서는 플랫폼별 스레드 관리나 OpenMP, TBB 같은 서드파티 라이브러리에 의존해야 했습니다.모던 C++20에서는 Ranges 라이브러리를 통해 알고리즘 파이프라인을 선언적으로 구성할 수 있으며, 병렬 알고리즘 지원을 통해 표준 라이브러리 레벨에서 병렬화를 쉽게 도입할 수 있습니다. 이렇게 하면 코드 가독성과 유지보수성이 대폭 개선되며, 성능 향상을 위한 병렬화도 간단히 적용할 수 있습니다.관련 참고 자료:C++20 RangesParallel al..
초창기 C++에서는 컨테이너를 순회하기 위해 전통적인 for 루프나 반복자(iterator)를 명시적으로 사용하는 패턴이 흔했습니다. 이런 방식은 인덱스나 반복자 관리에 번거로움이 있었고, 컨테이너 타입이 바뀌면 루프 조건을 바꾸는 등 유지보수가 어려웠습니다.모던 C++에서는 이러한 문제를 해소하기 위해 range-based for 루프와 C++20 Ranges 라이브러리가 등장했습니다. range-based for 루프를 통해 컨테이너 순회를 단순화하고, Ranges 라이브러리를 사용하면 필터링, 변환 등의 파이프라인 스타일 알고리즘을 선언적으로 표현할 수 있습니다. 이로써 코드 가독성과 유지보수성이 크게 향상됩니다.관련 참고 자료:Range-based for loopC++20 Ranges 라이브러리과..
앞서 기본 구현을 통해 groupby, permutations, product를 C++로 옮기는 방법을 살펴봤습니다. 여기서는 C++20의 Concepts와 Ranges 라이브러리를 활용해 정교한(또는 확장된) 구현 방법을 간단히 예시로 보여드리겠습니다.파이썬스럽다는 것은 단순히 기능을 흉내내는 데 그치지 않고, 타입 안정성, 가독성, 모듈성까지 고려하는 것입니다. Concepts로 입력 타입을 제약하거나, Variadic Template로 product를 여러 컨테이너에 확장하는 예제를 살펴보죠.정교한(또는 확장된) 구현 예제1. groupby에 Concepts 적용하기groupby는 연속된 원소를 key 함수 결과에 따라 그룹화합니다. 여기서 key 함수는 원소를 받아 어떤 key로 매핑하는 Call..
이제까지 파이썬 itertools와 more-itertools의 다양한 함수를 C++로 옮기며, 현대 C++이 제공하는 Ranges, Concepts, lazy evaluation을 통해 얼마나 파이썬스러운 코드를 구현할 수 있는지 확인했습니다. 이번에는 takewhile, dropwhile, 그리고 accumulate를 C++에서 흉내 내는 방법을 살펴보겠습니다.먼저 파이썬에서 이 함수들이 어떻게 동작하는지 간단히 살펴볼까요?from itertools import takewhile, dropwhile, accumulate# takewhile(predicate, iterable)# predicate가 참인 동안만 원소를 반환하다가, 거짓이 되는 순간 멈춤data = [1,2,3,4,5,1,2]for x ..