우리가 실무에서 소프트웨어를 개발하다 보면 "이 기능을 재사용할 수 있게 만들자", "내부 구현은 감추고 외부에는 필요한 기능만 제공하자"는 말을 자주 듣게 됩니다. 이런 설계 철학의 중심에는 바로 ADT (Abstract Data Type, 추상 데이터 타입)가 있습니다.
이번 글에서는 ADT의 개념과 실무에서의 활용 방식, 그리고 C#에서의 구현 예시까지 자세히 살펴보겠습니다.
1. ADT란?
ADT (Abstract Data Type)는 이름 그대로 "추상적인 데이터 타입"을 말합니다.
즉, 어떤 데이터와 그 데이터를 다루는 일련의 연산들을 묶어 하나의 타입처럼 정의하고, 외부에서는 이 연산들을 통해서만 데이터를 접근하도록 만드는 방식입니다.
예를 들어, 선풍기의 전원 버튼, 회전 버튼, 풍속 조절 버튼만을 외부에서 사용하고 내부 회로를 몰라도 선풍기를 사용할 수 있는 것과 비슷합니다.
핵심 요소
- 데이터: 내부에 저장되는 값
- 연산: 데이터를 다루는 메서드들
- 캡슐화: 내부 데이터는 숨기고, 메서드만 외부에 노출
2. ADT를 사용하는 이유
ADT를 사용하면 다음과 같은 장점이 있습니다:
| 캡슐화 | 내부 구현을 감추고 인터페이스만 제공하여 외부 코드가 쉽게 사용 가능 |
| 유지보수성 | 내부 코드 변경 시에도 외부에 영향이 없음 |
| 재사용성 | 다양한 상황에서 동일한 ADT를 재사용 가능 |
| 오류 방지 | 직접 접근을 막음으로써 잘못된 값 변경을 방지 |
3. Code Complete2에서 설명하는 ADT 예시
책에서는 폰트 설정을 예로 들고 있습니다.
만약 ADT 없이 임시방편으로 구현하면:
currentFont.size = 16; // 픽셀
반면 ADT를 사용하면:
currentFont.SetSizeInPoints(12);
이 방식이 더 명확하고, 내부 구조가 변경되더라도 외부 코드는 영향을 받지 않습니다.
그리고 중요한 점:
같은 의미를 가진 데이터를 두 개 다 저장하면 안 됩니다.
currentFont.sizeInPixels = 16;
currentFont.sizeInPoints = 12;
이렇게 하면 어떤 값이 진짜인지 혼란이 생기고, 데이터 불일치 문제가 발생합니다.
4. C#에서의 ADT 구현 예시
public class FontOption
{
private int sizeInPixels;
public void SetSizeInPoints(int pt)
{
sizeInPixels = PointsToPixels(pt);
}
public int GetSizeInPixels() => sizeInPixels;
public int GetSizeInPoints() => PixelsToPoints(sizeInPixels);
private int PointsToPixels(int pt) => (int)(pt * 1.333);
private int PixelsToPoints(int px) => (int)(px / 1.333);
}
- 내부 데이터(sizeInPixels)는 private으로 숨기고
- 외부에서는 SetSizeInPoints(), GetSizeInPoints()만 사용하도록 유도합니다.
5. ADT가 유용한 경우 vs 그렇지 않은 경우
유용한 경우
- 은행 계좌 객체 (입금/출금만 허용)
- 설정값 객체 (자동 변환, 유효성 검증 포함)
- 연결 객체 (DB 커넥션, 네트워크 소켓 등)
유용하지 않은 경우
- 단순 값만 저장하는 객체 (ex: Point(x, y))
- 처리 없이 값을 바로 쓰는 경우
- 성능이 극도로 중요하고 간접 접근이 부담되는 경우
6. 마무리 요약
| 개념 | 설명 |
| ADT란? | 데이터와 데이터를 다루는 연산을 묶은 추상 타입 |
| 핵심 요소 | 데이터 은닉 + 메서드 노출 (캡슐화) |
| 장점 | 유지보수성, 재사용성, 오류 방지 |
| C# 구현 | 클래스와 private 변수, public 메서드 사용 |
ADT는 단순히 설계 이론이 아닌, 실무 개발에서 코드의 유지보수성과 확장성을 높이는 매우 중요한 도구입니다.
7. ADT를 공부하면서
내가 이해한 ADT는 결국 "클래스를 따로 만들어서 해당 기능을 가져다 쓰는 것"이다.
→ 그게 왜 연산을 통해서만 접근한다고 하는 건지?
→ 왜 추상 '데이터 타입'이라는 표현을 쓰는지?
→ ADT 구현도 결국 내가 클래스를 만들어서 함수 작성하는 건데 그게 ADT랑 뭐가 다른지?
클래스를 만들었다고 해서 그게 ADT인건 아니고, ADT 원칙(구현 은닉, 연산만 제공)을 지키는 클래스를 만들었을 때 이를 ADT 구현이라고 부를 수 있습니다.
"중요한건 어떻게 구현했는가"가 아니라 "어떤 철학을 지켰는가"입니다.
- 단순히 클래스를 만들어 놓고 내부 구조를 외부에 공개한다면 → 그건 ADT가 아님
- 클래스 내부 구현을 감추고, 오직 제공된 연산만 외부에서 접근 가능하다면 → 그건 ADT
즉, ADT는 클래스보다 더 추상적이고 철학적인 수준의 설계 원칙이에요.
1. 클래스 만들어서 사용하는 것과 ADT는 다르지 않다 (구현 vs 개념)
클래스를 따로 만들어서 해당 기능을 쓰는 것이 바로 ADT를 실무에서 구현하는 방법입니다.
- class FontOption 같은 클래스를 만들고
- 외부에서는 .ChangeFontSize(12) 같은 메서드(= 연산)만 사용하게 만들며
- 내부 구현은 감춰놓는 것
➡ 이게 정보 은닉(Encapsulation)이고, 동시에 추상 데이터 타입의 철학입니다.
ADT는 "데이터 + 연산"의 집합이다.
"이 데이터는 이 연산들을 통해서만 다룰 수 있다."는 게 핵심 개념이다.
2. 왜 “연산을 통해서만 접근”해야 한다고 하는가?
이건 ‘직접 값을 건드리지 말라’는 원칙에서 나옵니다.
예시:
만약 내부 구조가 point 기준에서 pixel로 바뀌면?
- 첫 번째 예시는 모든 코드 수정해야 함
- 두 번째 예시는 SetSizeInPoints만 바꾸면 됨
그래서 ADT에서는 외부에서는 무조건 연산(메서드)만 사용해야 한다고 강조합니다.
3. 왜 ‘데이터 타입’이라고 부를까?
C#에서 말하는 int, string 같은 데이터 타입은 시스템이 제공하는 내장 타입입니다.
ADT는 우리가 정의하는 사용자 정의 타입입니다.
즉, 이 말은 다음을 뜻합니다:
| int, float 등 | FontOption, Stack, Queue 등 |
| 숫자를 저장하는 용도 | 폰트 속성을 관리하는 기능 + 연산을 포함하는 구조 |
타입이란 건 "어떻게 써야 하는가에 대한 규칙"이니까요.
'개발 서적 > Code Complete2' 카테고리의 다른 글
| 1-2 소프트웨어 개발의 이해를 돕기 위한 비유 (6) | 2025.08.12 |
|---|