C++ 예제로 배우는 소프트웨어 설계 기법 (8) — 메뉴 시스템과 컴포지트(Menu System)
메뉴는 실행할 수 있는 항목(Open, Save)과 다른 메뉴를 담는 팝업 메뉴(File, Recent)로 이루어지고, 팝업 안에 팝업이 다시 들어가는 트리 구조다. 두 종류를 따로 다루면 "이 항목이 팝업인가?"를 묻는 분기가 곳곳에…
메뉴는 실행할 수 있는 항목(Open, Save)과 다른 메뉴를 담는 팝업 메뉴(File, Recent)로 이루어지고, 팝업 안에 팝업이 다시 들어가는 트리 구조다. 두 종류를 따로 다루면 "이 항목이 팝업인가?"를 묻는 분기가 곳곳에…
6편에서는 변하는 정책을 가상 함수나 인터페이스 객체로 분리했다. 그런데 단일 스레드에서만 쓰는 리스트도 동기화 정책을 가상 함수로 받으면, 아무 일도 하지 않는 lock()을 매번 간접 호출하는 비용을 낸다. 정책을 실행…
입력창(LineEdit)은 키 입력을 받아 문자열을 만드는 흐름은 늘 같다. 반면 숫자만 받을지, 우편번호 5자리를 받을지 같은 검증 규칙은 쓰는 곳마다 다르다. 이렇게 변하지 않는 코드와 변하는 코드를 어떻게 나누느냐가 설계의…
사각형, 원, 삼각형을 그리고 복사·붙여넣기하고 파일에서 다시 읽어 들이는 도형 편집기는 객체지향 설계를 연습하는 고전적인 예제다. 도형 종류를 값으로 구분해 switch로 처리하면 새 도형을 추가할 때마다 흩어진 switch를 모두 찾아…
설정, 로거, 입력 장치처럼 프로그램 전체에 하나만 있어야 하는 객체가 있다. 전역 변수로 두면 누구나 새로 만들 수 있고, 생성 시점도 통제할 수 없다. 싱글톤(Singleton)은 생성자를 막고 정적 접근 함수…
Win32 SetTimer 같은 C 타이머 API는 콜백에 타이머 id만 넘겨준다. 시계 객체 여러 개가 각자 타이머를 걸면, static 콜백 안에서는 어느 객체의 타이머가 울렸는지 알 수 없다. 1편의 Thread는 void*로…
pthread_create 같은 OS 스레드 API는 void* (*)(void*) 형태의 C 함수 포인터만 받는다. 스레드에서 객체의 멤버 함수를 돌리고 싶어도 그대로 넘길 수 없다. 그래서 C 콜백 API를 클래스로 감싸는 첫 단계가…
지난 글에서 dynamic_cast는 상속 그래프를 탐색하느라 typeid 비교보다 10배 넘게 느렸고, -fno-rtti로 빌드하면 아예 쓸 수 없었다. 그래서 LLVM/Clang처럼 타입 판정이 잦고 -fno-rtti로 빌드하는 프로젝트는 RTTI를 직접 구현한다. 각 객체에…
기반 클래스 포인터만 들고 있는데 실제 객체가 어떤 타입인지 알아야 할 때가 있다. 이벤트 큐에서 꺼낸 객체를 타입별 핸들러로 보내거나, 특정 파생 타입에만 있는 기능을 쓰는 경우다. C++은 실행 시점…