객체 지향 프로그래밍은 절차적/구조적 프로그램의 어깨를 딛고 있다.
객체 지향 언어를 이해하기 위해 절차적/구조적 프로그래밍을 아는 것이 큰 도움이 된다.
따라서, 보통 객체지향 프로그래밍을 설명할 때 언급하는 프로그래밍들을 간략하게 설명한다.
영어로는 Sequential Programming이며, 비구조적 프로그래밍이라고도 한다.
이는 코드로 따지자면, 함수 하나에 모든 기능을 구현한 것으로 보인다. 구조가 없이, 위에서 아래로 흘러가는 것이다.
이를 테면, 사용자로부터 2개의 숫자를 입력 받아 더하는 프로그램을 만든다고 하자.
그러면 순차적 프로그래밍에서는 아래와 같이 코드를 짤 수 있다. 코드는 ChatGPT의 도움을 받았다.
#include <stdio.h>
int main() {
// 프로그램 시작
printf("두 숫자를 입력하세요.\n");
// 1. 사용자로부터 첫 번째 숫자 입력 받기
double num1;
printf("첫 번째 숫자: ");
scanf("%lf", &num1);
// 2. 사용자로부터 두 번째 숫자 입력 받기
double num2;
printf("두 번째 숫자: ");
scanf("%lf", &num2);
// 3. 입력값에 대한 처리: 두 숫자 더하기
double result = num1 + num2;
// 4. 처리된 결과 출력
printf("두 숫자의 합: %.2lf\n", result);
// 5. 프로그램 종료
printf("프로그램을 종료합니다.\n");
return 0;
}
goto 문은 프로그램에서 특정 위치로 이동하는 명령문으로, 실행 흐름을 명시적으로 변경할 수 있다.
순차적 프로그래밍에서는 위에서 아래로 코드를 실행 시키는데, 예를 들어 어떤 조건에서는 특정 위치로 건너 뛰어서 실행시키고 싶을 때 사용한다.
아래 코드는 사용자로부터 정수를 입력 받았을 때
#include <stdio.h>
int main() {
int userInput;
// 사용자로부터 정수 입력 받기
printf("정수를 입력하세요: ");
scanf("%d", &userInput);
// 입력값이 0보다 작으면 error 레이블로 이동
if (userInput < 0) {
goto error;
}
// 입력값이 0보다 크거나 같으면 정상적인 결과 출력
printf("입력한 수: %d\n", userInput);
return 0;
// 오류 메시지 출력을 위한 레이블
error:
printf("오류: 입력값이 0보다 작습니다.\n");
return 1;
}
goto를 사용하면 프로그램의 실행 순서를 이리저리 이동할 수 있게 된다. 그러나 이동이 잦아지면 코드를 이해하기에 복잡해질 가능성이 있다.
게다가 goto를 이용한 이동은 프로그램을 논리적으로 잘 구성하면 모두 피할 수 있는 것들이기 때문에, 자바에서는 원천적으로 사용을 금지하고 있다.
따라서 위 예제 코드들도 C언어를 사용했다.
goto의 폐해로 자바는 아예 goto를 예약어로 선점해 사용하지 못하게 막아두었다.
자바 공식 문서에서 goto는 not used(사용 안함)임을 확인할 수 있다.
goto를 사용하지 말자!
영어로는 procedural programming라고 한다.
순차적 프로그래밍에서는 중복되는 코드가 발생할 수밖에 없다.
이때, 중복되는 기능이나 관련 없는 기능들을 따로 분리함으로써 구조를 만든 프로그래밍 패러다임이 바로 절차적 프로그래밍이다.
이렇게 분리해낸 단위를 프로시저라고 하며, 보통 함수를 말한다.
순차적 프로그래밍의 예제를 절차적 프로그래밍으로 변경한 결과이다.
#include <stdio.h>
// 함수 선언
void printWelcomeMessage();
double getUserInput(char message[]);
double addNumbers(double num1, double num2);
void printResult(double result);
void printProgramExitMessage();
int main() {
// 프로그램 시작
printWelcomeMessage();
// 1. 사용자로부터 첫 번째 숫자 입력 받기
double num1 = getUserInput("첫 번째 숫자: ");
// 2. 사용자로부터 두 번째 숫자 입력 받기
double num2 = getUserInput("두 번째 숫자: ");
// 3. 입력값에 대한 처리: 두 숫자 더하기
double result = addNumbers(num1, num2);
// 4. 처리된 결과 출력
printResult(result);
// 5. 프로그램 종료
printProgramExitMessage();
return 0;
}
// 환영 메시지 출력 함수
void printWelcomeMessage() {
printf("두 숫자를 입력하세요.\n");
}
// 사용자 입력 받기 함수
double getUserInput(char message[]) {
double input;
printf("%s", message);
scanf("%lf", &input);
return input;
}
// 두 숫자 더하기 함수
double addNumbers(double num1, double num2) {
return num1 + num2;
}
// 결과 출력 함수
void printResult(double result) {
printf("두 숫자의 합: %.2lf\n", result);
}
// 프로그램 종료 메시지 출력 함수
void printProgramExitMessage() {
printf("프로그램을 종료합니다.\n");
}
함수를 쓰자!
구조적 프로그래밍(structured programming)은 절차적 프로그래밍의 하위 개념으로 볼 수 있다.
구조적 프로그래밍은 함수를 쓰라는 것이다. 이렇게 함수를 사용하면 다음과 같은 이점이 있다.
구조적 프로그래밍의 지침 중에는 공유 사용 시 문제가 발생하기 쉬운 전역 변수보다는 지역 변수를 쓰라는 것도 있다.
그림으로 보자면 아래와 같을 것이다.
인간은 이미 객체지향 방식으로 생각하고 있다.
절차적/구조적 프로그래밍까지의 과정은 인간이 기계를 이해하려는 노력에서 크게 벗어나지 못했다. 특히 포인터의 개념은 기계 수준으로 눈높이를 낮추지 않으면 이해하기 매우 힘든 부분이다.
이러한 기계 종속적인 개발에서 벗어나, 현실 세계처럼 프로그래밍할 수 없을까라는 고민 속에서 객체 지향의 개념이 탄생했다.
우리가 주변에서 사물을 인지하는 방식대로 프로그래밍할 수 있지 않겠는가?
객체지향이 현실 세계를 반영한다는 증거는 바로 객체다.
사물을 하나하나 이해하기보다는 사물을 분류(class)해서 이해하는 것이 인간의 인지법이다.
이를 테면, 우리는 다음과 같이 분류한다.
여기서 사람이라는 분류 안의 객체(Object)들은 나이, 몸무게, 키 등의 속성(property)과 먹다, 자다, 울다 등의 행위(method)를 가지고 있다.
다시 정리하자면, 객체 지향은 실제 사물을 인지 및 사고하는 방식대로 객체 단위의 프로그래밍이 가능하다.
즉, 인간의 인지 및 사고 방식까지 프로그래밍에 접목하는 인간(개발자) 지향을 실천하고 있는 것이다. 그래서 객체 지향은 직관적이라고 할 수 있다.
절차적/구조적 프로그래밍에서 나온 개념들과 자바 언어는 다음과 같이 연결 시킬 수 있다.
결론적으로, 객체 지향 언어에서 절차적/구조적 프로그래밍의 유산은 메서드 안에서 확인할 수 있다.
객체 지향 프로그래밍에서 제어문이 존재할 수 있는 유일한 공간은 바로 메서드 내부이기 때문이다.
둘은 다르지 않다.
절차적/구조적 프로그래밍에서는 함수라고 불렀는데, 객체 지향에서는 조금 다르게 불러야 할 것 같아서 메서드라고 이름 붙였다고 한다.
그래도 굳이 차이점을 찾는다면 함수는 클래스나 객체와 아무 관계가 없지만, 메서드는 반드시 클래스 정의 안에 존재해야 한다는 것이다.
💡 객체 지향 언어에서 클래스 외부에 존재할 수 있는 것은 없다.
import 문은 편의 기능이며, 타이핑을 적게 하기 위한 편의 기능일 뿐이다.
인터넷에서 객체지향 프로그래밍을 검색하다 보면, 자주 ‘절차지향 프로그래밍’이라는 문장을 볼 수 있을 것이다.
그리고 이런 경우, 절차지향과 객체지향을 반대되는 개념으로 설명할 때가 많다.
그러나 절차지향이라는 단어부터가 틀린 것이다. 정확히 말하자면 ‘절차적’이 옳은 표현이다.
프로그래밍의 기본 틀은 절차를 기반으로 두고 있다. 객체지향도 절차적 프로그래밍을 기반으로 객체라는 것을 도입한 것이다.
즉, 두 개념은 상반되는 개념이 아니다.
절차적 프로그래밍은 ‘데이터를 중심으로 함수’를 만들어 쓰는 편이고, 객체지향은 ‘데이터와 기능(함수)들을 묶어 하나의 객체’로 만들어 쓴다.
보통, 아래의 기준에 따라 절차적 언어와 객체지향 언어가 나뉜다.
보통은 위 기준을 만족하면 객체지향, 만족하지 않으면 절차적 성격이 강해진다.
📔 스프링 입문을 위한 자바 객체 지향의 원리와 이해
절차적/구조적 프로그래밍 - procedural/structed programming